home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
except1.zip
/
HeapMgr.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-23
|
29KB
|
857 lines
#pragma title("Exception Example -- Version 1.0 -- (HeapMgr.C)")
#pragma subtitle(" Memory Manager - Interface Definitions")
#pragma info(noext)
#define INCL_DOS /* Include OS/2 DOS Kernal */
#define INCL_WIN /* Include OS/2 PM Windows Interface */
#include <os2.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include "heapmem.h"
/* This module contains the memory routines used by the custom */
/* controls. */
/* Filename: HeapMgr.C */
/* Version: 3.0 */
/* Created: 1994-08-23 */
/* Revised: 1994-08-23 */
/* Routines: HHEAPMEM HeapAlloc(ULONG cbInitial, ULONG cbNewBlks); */
/* VOID HeapRelease(HHEAPMEM hHeap); */
/* ULONG HeapSize(HHEAPMEM hHeap); */
/* VOID HeapStatus(HHEAPMEM hHeap, PULONG pcBlocks, */
/* PULONG pulSize, PULONG pulUsed, */
/* PULONG pulFree, PULONG pulUnused, */
/* PULONG pulOverhead); */
/* VOID HeapDisplayStatus(HHEAPMEM hHeap); */
/* PVOID HeapMalloc(HHEAPMEM hHeap, ULONG cbSize); */
/* PVOID HeapCalloc(HHEAPMEM hHeap, ULONG cItems, */
/* ULONG cbSize); */
/* PVOID HeapRealloc(HHEAPMEM hHeap, PVOID pv, */
/* ULONG cbSize); */
/* VOID HeapFree(HHEAPMEM hHeap, PVOID pv); */
/* Copyright ╕ 1989-1995 Prominare Inc. All Rights Reserved. */
/* -------------------------------------------------------------------- */
typedef struct _HEAPBLK
{
ULONG cb; /* Block Size */
ULONG cbUsed; /* Used Block Size */
struct _HEAPBASE *phbase; /* Base Block Pointer */
struct _HEAPBLK *phblkFree; /* User Memory Pointer */
} HEAPBLK ; /* hblk */
typedef HEAPBLK *PHEAPBLK;
typedef struct _HEAPBASE
{
ULONG cbInitial; /* Initial Heap Size */
ULONG cbNewBlks; /* New Block Allocation Size */
ULONG cBlksUsed; /* Blocks Used Count */
PHEAPBLK phblkStart; /* Starting User Memory Pointer */
PHEAPBLK phblkLast; /* Starting Free User Memory Pointer */
PHEAPBLK phblkFree; /* Starting Free List Memory Pointer */
struct _HEAPBASE *phbaseNext; /* Next Block Pointer */
struct _HEAPBASE *phbaseLast; /* Last Block Pointer */
} HEAPBASE ; /* hbase */
typedef HEAPBASE *PHEAPBASE;
#pragma subtitle(" Heap Manager - Heap Allocation Function")
#pragma page( )
/* --- HeapAlloc --------------------------------------- [ Public ] --- */
/* */
/* This function is used to allocate a heap for the user using */
/* heap start size requested along with the resizing values. */
/* The heap returns a handle which is the actual memory address */
/* such that the entire heap can be released quickly. */
/* */
/* Upon Entry: */
/* */
/* ULONG cbInitial; = Initial Heap Size */
/* ULONG cbNewBlks; = New Heap Blocks Size */
/* */
/* Upon Exit: */
/* */
/* HeapAlloc = Heap Handle */
/* */
/* -------------------------------------------------------------------- */
HHEAPMEM HeapAlloc(ULONG cbInitial, ULONG cbNewBlks)
{
PHEAPBASE phbase; /* Heap Base Pointer */
/* Check to see if the initial heap size is the */
/* default */
if ( cbInitial == HALLOC_DEFAULT )
cbInitial = 32768UL;
/* Check to see if the initial block size is the */
/* default */
if ( cbNewBlks == HALLOC_DEFAULT )
cbNewBlks = 32768UL;
/* Allocate the base memory for the heap with it */
/* being totally committed */
if ( DosAllocMem((PPVOID)(PVOID)&phbase, cbInitial, PAG_READ | PAG_WRITE | PAG_COMMIT) )
return(0UL);
/* Check to see if the size requested was not an */
/* even page size in which case more memory has */
/* been allocated than requested. In this case, */
/* the memory routines will utilize the memory */
/* as though it was normally allocated. */
if ( cbInitial % 4096UL )
phbase->cbInitial = ((cbInitial / 4096UL) + 1UL) * 4096UL;
else
phbase->cbInitial = cbInitial;
/* Check to see if the new block size is not an */
/* even page size in which case more memory has */
/* been allocated than requested. In this case, */
/* the memory routines will utilize the memory */
/* as though it was normally allocated. */
if ( cbNewBlks % 4096UL )
phbase->cbNewBlks = ((cbNewBlks / 4096UL) + 1UL) * 4096UL;
else
phbase->cbNewBlks = cbNewBlks;
/* Force the first to have a used block count */
/* even though no blocks have been allocated. */
/* By doing this, the first block cannot be */
/* released. */
phbase->cBlksUsed = 1UL;
/* Return the memory address as the handle for */
/* the heap */
return((HHEAPMEM)(phbase->phbaseLast = phbase));
}
#pragma subtitle(" Heap Manager - Heap Release Function")
#pragma page( )
/* --- HeapRelease ------------------------------------- [ Public ] --- */
/* */
/* This function is used to release a heap for the user using */
/* the heap handle that was returned through the HeapAlloc( ) */
/* function. The routine walks the heap blocks releasing each */
/* block. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* */
/* Upon Exit: */
/* */
/* Nothing */
/* */
/* -------------------------------------------------------------------- */
VOID HeapRelease(HHEAPMEM hHeap)
{
PHEAPBASE phbase = (PHEAPBASE)hHeap; /* Heap Base Pointer */
PHEAPBASE phbaseNext; /* Heap Base Pointer */
/* Move through the heap blocks releasing the */
/* allocated blocks back to the system */
while ( phbase )
{
phbaseNext = phbase->phbaseNext;
DosFreeMem((PVOID)phbase);
phbase = phbaseNext;
}
}
#if defined(DEBUG_LISTBOX)
#pragma subtitle(" Heap Manager - Heap Release Function")
#pragma page( )
/* --- HeapSize ---------------------------------------- [ Public ] --- */
/* */
/* This function is used to determine the size of the heap. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* */
/* Upon Exit: */
/* */
/* HeapSize = Size of Heap */
/* */
/* -------------------------------------------------------------------- */
ULONG HeapSize(HHEAPMEM hHeap)
{
PHEAPBASE phbase; /* Heap Base Pointer */
ULONG ulSize = 0UL; /* Heap Size Holder */
/* Convert the heap handle to the heap base */
/* address */
phbase = (PHEAPBASE)hHeap;
/* Move through the heap blocks counting the */
/* allocated blocks size for the total memory */
/* allocated in the heap */
while ( phbase )
{
ulSize += phbase->cbInitial;
phbase = phbase->phbaseNext;
}
/* Return the allocated size of the heap */
return(ulSize);
}
#pragma subtitle(" Heap Manager - Heap Status Function")
#pragma page( )
/* --- HeapStatus -------------------------------------- [ Public ] --- */
/* */
/* This function is used to determine the status of the heap by */
/* gathering various statistics for the heap. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* PULONG pcBlocks; = Blocks Count Pointer */
/* PULONG pulSize; = Total Heap Size Pointer */
/* PULONG pulUsed; = Total Used Pointer */
/* PULONG pulFree; = Total Free Pointer */
/* PULONG pulUnused; = Total Unused Pointer */
/* PULONG pulOverhead; = Total Overhead Pointer */
/* */
/* Upon Exit: */
/* */
/* Nothing */
/* */
/* -------------------------------------------------------------------- */
VOID HeapStatus(HHEAPMEM hHeap, PULONG pcBlocks, PULONG pulSize,
PULONG pulUsed, PULONG pulFree, PULONG pulUnused, PULONG pulOverhead)
{
PHEAPBASE phbase = (PHEAPBASE)hHeap; /* Heap Base Pointer */
PHEAPBLK phblk; /* Heap Base Pointer */
*pcBlocks = *pulSize = *pulUsed = *pulFree = *pulUnused = *pulOverhead = 0UL;
/* Move through the heap blocks counting the */
/* allocated blocks size for the total memory */
/* allocated in the heap */
while ( phbase )
{
++*pcBlocks;
*pulSize += phbase->cbInitial;
*pulUnused += (phbase->cbInitial - sizeof(HEAPBASE));
*pulOverhead += sizeof(HEAPBASE);
phblk = (PVOID)((PBYTE)phbase + sizeof(HEAPBASE));
while ( (phblk <= phbase->phblkLast) && phblk->cb )
{
if ( phblk->cbUsed )
{
*pulUsed += phblk->cb;
*pulOverhead += sizeof(HEAPBLK);
*pulUnused -= (phblk->cb + sizeof(HEAPBLK));
}
phblk = (PVOID)((PBYTE)phblk + phblk->cb + sizeof(HEAPBLK));
}
phblk = phbase->phblkFree;
while ( phblk )
{
if ( phblk->cb )
{
*pulFree += phblk->cb;
*pulOverhead += sizeof(HEAPBLK);
*pulUnused -= (phblk->cb + sizeof(HEAPBLK));
}
phblk = phblk->phblkFree;
}
phbase = phbase->phbaseNext;
}
}
#pragma subtitle(" Heap Manager - Heap Status Function")
#pragma page( )
/* --- HeapDisplayStatus ------------------------------- [ Public ] --- */
/* */
/* This function is used to display the status of the heap by */
/* gathering various statistics for the heap. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* */
/* Upon Exit: */
/* */
/* Nothing */
/* */
/* -------------------------------------------------------------------- */
VOID HeapDisplayStatus(HHEAPMEM hHeap)
{
CHAR szStrBuf[256]; /* Display Buffer */
ULONG cBlocks; /* Blocks Count */
ULONG ulFree; /* Free Memory Count */
ULONG ulOverhead; /* Overhead Count */
ULONG ulSize; /* Total Size Count */
ULONG ulUnused; /* Unused Count */
ULONG ulUsed; /* Used Count */
if ( hHeap )
{
HeapStatus(hHeap, &cBlocks, &ulSize, &ulUsed, &ulFree, &ulUnused, &ulOverhead);
sprintf(szStrBuf, "Heap Size: %d\nHeap Used: %d (%d%%)\nHeap Free: %d (%d%%)\nHeap Unused: %d (%d%%)\nHeap Overhead: %d (%d%%)",
ulSize, ulUsed, (ulUsed * 100UL) / ulSize, ulFree, (ulFree * 100UL) / ulSize,
ulUnused, (ulUnused * 100UL) / ulSize, ulOverhead, (ulOverhead * 100UL) / ulSize);
}
else
memcpy(szStrBuf, "NULL heap handle.", 18);
WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szStrBuf,
"Heap Debug Status Report", 1UL,
MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
}
#endif
#pragma subtitle(" Heap Manager - Heap Suballocation Function")
#pragma page( )
/* --- HeapMalloc -------------------------------------- [ Public ] --- */
/* */
/* This function is used to allocate a block of memory from the */
/* heap using the heap handle that was returned through the */
/* HeapAlloc( ) function. The routine walks the heap blocks */
/* releasing each looking for either the first free block */
/* that can accommodate the request or the start of free memory */
/* which is first. If there is no more memory within the heap */
/* block, another block is allocated. The memory block returned */
/* unlike the traditional malloc( ) will be initialized to 0 */
/* for all of the memory elements. The placement of each */
/* subblock is such that the housekeeping structure starts on a */
/* 4 byte boundary. To achieve this, the memory being requested */
/* is padded as required. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* ULONG cbSize; = Memory Size Requested */
/* */
/* Upon Exit: */
/* */
/* HeapMalloc = 0 : Error Return, Out of Memory */
/* = >0 : Memory Address */
/* */
/* -------------------------------------------------------------------- */
PVOID HeapMalloc(HHEAPMEM hHeap, ULONG cbSize)
{
PHEAPBASE phbase = (PHEAPBASE)hHeap; /* Heap Base Pointer */
PHEAPBASE phbaseNext; /* Heap Base Pointer */
PHEAPBASE phbaseStart; /* Heap Base Pointer */
PHEAPBLK phblk; /* Heap Base Pointer */
PHEAPBLK phblkPrev; /* Heap Base Pointer */
PHEAPBLK phblkNext; /* Heap Base Pointer */
ULONG cbNewBlks; /* New Block Size */
ULONG cb = (cbSize / 4L + 1L) * 4L;/* Block Size */
/* Walk through the base addresses looking for */
/* a subblock of memory that can satisfy the */
/* request */
while ( phbase )
{
/* Get the start of the free memory subblocks */
if ( (phblk = phbase->phblkFree) != NULL )
{
while ( phblk )
{
/* Have found a subblock not being used, see if */
/* the subblock is large enough for the request */
if ( phblk->cb >= cb )
{
if ( phblk->cb > (cb + sizeof(HEAPBLK)) )
{
/* Form the address of the start of memory */
/* subblock by creating the block from the high */
/* part of the subblock */
phblkNext = (PHEAPBLK)((PBYTE)phblk + phblk->cb - cb);
/* Save the amount of memory being used within */
/* the subblock */
phblkNext->cb = cb;
phblkNext->phbase = phbase;
/* Adjust the size of the block allocated from */
/* to be less the size of the block requested */
/* and the block overhead */
phblk->cb -= (cb + sizeof(HEAPBLK));
/* Set the current pointer to the new subblock */
phblk = phblkNext;
}
else
/* No subblock division possible, update the */
/* first list pointers to exclude the block */
if ( phblk == phbase->phblkFree )
phbase->phblkFree = phblk->phblkFree;
else
phblkPrev->phblkFree = phblk->phblkFree;
/* Save the requested size in the used portion */
phblk->cbUsed = cbSize;
phblk->phblkFree = NULL;
++phblk->phbase->cBlksUsed;
/* Clear the block of memory as is the norm and */
/* return the address back to the User */
memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
}
/* Current free list pointer is not adequate for */
/* the request, check the next one */
phblkPrev = phblk;
phblk = phblkPrev->phblkFree;
}
}
/* Check to see if the last block has been */
/* defined for the current memory block */
if ( phbase->phblkLast )
{
/* Check to see if the last block of the current */
/* memory block has been released in which case */
/* it would not have been added to the free list */
/* chain since the last block would then have */
/* been undefined */
if ( phbase->phblkLast->cbUsed == 0UL )
{
/* Last block of the current memory block */
/* is a free block, check to see if the block */
/* can be sub-divided */
if ( phbase->phblkLast->cb >= cb )
{
phblk = phbase->phblkLast;
/* See if the block is dividable */
if ( phbase->phblkLast->cb > (cb + sizeof(HEAPBLK)) )
{
/* Form the address of the start of memory */
/* subblock by creating the block from the high */
/* part of the subblock */
phblkNext = (PHEAPBLK)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) + cb);
/* Update the next last block pointer to take */
/* into consideration the new block being */
/* allocated */
phblkNext->phbase = phbase;
phblkNext->cb = phbase->phblkLast->cb - (cb + sizeof(HEAPBLK));
phblkNext->cbUsed = 0UL;
phblkNext->phblkFree = NULL;
/* Update the last block pointer to point to the */
/* next block created from the larger block */
phbase->phblkLast = phblkNext;
/* Save the amount of memory being used within */
/* the subblock */
phblk->cb = cb;
}
/* Save the requested size in the used portion */
phblk->cbUsed = cbSize;
phblk->phblkFree = NULL;
++phblk->phbase->cBlksUsed;
/* Clear the block of memory as is the norm and */
/* return the address back to the User */
memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
}
}
else
/* Check to see if no free subblocks found, in */
/* which case a new subblock needs to be added */
/* after the last current subblock */
if ( (((PBYTE)phbase->phblkLast + (sizeof(HEAPBLK) * 2L) + phbase->phblkLast->cb) + cb) <
((PBYTE)phbase + phbase->cbInitial) )
{
/* Using the address of the last subblock, */
/* calculate the address of the new subblock */
/* such that it is just after the block of */
/* memory being used by the User */
phbase->phblkLast = phblk = (PVOID)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) + phbase->phblkLast->cb);
/* Subblock is adequate for the memory request, */
/* save the requested size in the used portion */
phblk->cb = cb;
phblk->cbUsed = cbSize;
/* Save the base of the memory block to allow */
/* easy compaction of free memory blocks when */
/* memory is released */
phblk->phbase = phbase;
++phblk->phbase->cBlksUsed;
/* Clear the block of memory as is the norm and */
/* return the address back to the User */
memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
}
}
else
if ( (phbase->cbInitial - sizeof(HEAPBASE) - sizeof(HEAPBLK)) > cb )
{
/* No subblocks created yet, start the first */
/* subblock after the base housekeeping area */
phbase->phblkLast = phblk = phbase->phblkStart = (PVOID)((PBYTE)phbase + sizeof(HEAPBASE));
/* Save the requested size in the used portion */
phblk->cb = cb;
phblk->cbUsed = cbSize;
/* Save the base of the memory block to allow */
/* easy compaction of free memory blocks when */
/* memory is released */
phblk->phbase = phbase;
++phblk->phbase->cBlksUsed;
/* Clear the block of memory as is the norm and */
/* return the address back to the User */
memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
}
phbase = phbase->phbaseNext;
}
/* Convert the heap handle to the heap base */
/* address */
phbaseStart = (PHEAPBASE)hHeap;
/* Point to the next memory block */
phbase = phbaseStart->phbaseLast;
/* Last block found, check to see if the amount */
/* of memory requested is larger than the new */
/* block size in which case the full block is */
/* allocated */
if ( cb > (phbaseStart->cbNewBlks - sizeof(HEAPBASE) - sizeof(HEAPBLK)) )
/* Size of memory requested larger than the */
/* block size, calculate the amount of memory */
/* needed including the housekeeping records */
cbNewBlks = cb + sizeof(HEAPBASE) + sizeof(HEAPBLK);
else
cbNewBlks = phbaseStart->cbNewBlks;
/* Allocate the necessary memory */
if ( DosAllocMem((PPVOID)(PVOID)&phbaseNext, cbNewBlks, PAG_READ | PAG_WRITE | PAG_COMMIT) )
/* Error in allocating the memory, return NULL */
/* to indicate no memory was allocated */
return(NULL);
else
/* Save the new block address in the last block */
/* next pointer */
phbase->phbaseNext = phbaseStart->phbaseLast = phbaseNext;
/* Check to see if the new block size is not an */
/* even page size in which case more memory has */
/* been allocated than requested. In this case, */
/* the memory routines will utilize the memory */
/* as though it was normally allocated. */
if ( (phbaseNext->cbNewBlks = cbNewBlks) % 4096UL )
phbaseNext->cbInitial = ((cbNewBlks / 4096UL) + 1) * 4096UL;
else
phbaseNext->cbInitial = cbNewBlks;
/* Form the address of the start of memory */
/* subblock */
phbaseNext->phblkLast = phblk = phbaseNext->phblkStart = (PVOID)((PBYTE)phbaseNext + sizeof(HEAPBASE));
/* Save the amount of memory being used within */
/* the subblock */
phblk->cb = cb;
phblk->cbUsed = cbSize;
/* Save the base of the memory block to allow */
/* easy compaction of free memory blocks when */
/* memory is released */
phblk->phbase = phbaseNext;
++phblk->phbase->cBlksUsed;
/* Return the address of the User memory block */
return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
}
#pragma subtitle(" Heap Manager - Heap Suballocation Function")
#pragma page( )
/* --- HeapCalloc -------------------------------------- [ Public ] --- */
/* */
/* This function is used to release a heap for the user using */
/* the heap handle that was returned through the HeapAlloc( ) */
/* function. The routine uses the HeapMalloc( ) since it is */
/* designed to clear the memory allocated like a normal */
/* calloc( ) function. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* ULONG cItems; = Items Count */
/* ULONG cbSize; = Item Size */
/* */
/* Upon Exit: */
/* */
/* HeapCalloc = 0 : Error Return, Out of Memory */
/* = >0 : Memory Address */
/* */
/* -------------------------------------------------------------------- */
PVOID HeapCalloc(HHEAPMEM hHeap, ULONG cItems, ULONG cbSize)
{
return(HeapMalloc(hHeap, cItems * cbSize));
}
#pragma subtitle(" Heap Manager - Heap Re-allocation Function")
#pragma page( )
/* --- HeapRealloc ------------------------------------- [ Public ] --- */
/* */
/* This function is used to reallocate a block of memory for the */
/* user. If the block is smaller, the same memory is returned */
/* otherwise a new block is returned and the old block released. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* PVOID pv; = Current Memory Block Address */
/* ULONG cbSize; = Required Memory Size */
/* */
/* Upon Exit: */
/* */
/* HeapRealloc = 0 : Error Return, Out of Memory */
/* = >0 : Memory Address */
/* */
/* -------------------------------------------------------------------- */
PVOID HeapRealloc(HHEAPMEM hHeap, PVOID pv, ULONG cbSize)
{
PVOID pvNew; /* New Memory Block Address */
PHEAPBLK phblk; /* Heap Base Pointer */
/* Check to make sure that the pointer is not */
/* NULL which would cause a GP */
if ( pv == NULL )
return(NULL);
/* Form the address of the subblock housekeeping */
/* record */
phblk = (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
/* Determine if the size requested is smaller */
/* than the current block size in which case the */
/* the block size should be used and returned */
if ( phblk->cb >= cbSize )
{
phblk->cbUsed = cbSize;
return(pv);
}
else
/* New size larger than current block size, */
/* allocate a new block */
if ( (pvNew = HeapMalloc(hHeap, cbSize)) != NULL )
{
/* Transfer the memory from the old block to the */
/* new block */
memmove(pvNew, pv, phblk->cbUsed);
/* Release the memory block for the old block */
HeapFree(hHeap, pv);
/* Return the address of the new block */
return(pvNew);
}
else
/* Error occurred during the memory allocation, */
/* return NULL to indicate problem */
return(NULL);
}
#pragma subtitle(" Heap Manager - Heap Release Function")
#pragma page( )
/* --- HeapFree ---------------------------------------- [ Public ] --- */
/* */
/* This function is used to release a block of memory that has */
/* been allocated by the user. The routine performs free block */
/* compaction to allow for proper reallocation of unused blocks. */
/* */
/* Upon Entry: */
/* */
/* HHEAPMEM hHeap; = Heap Handle */
/* PVOID pv; = Address of User Memory to Release */
/* */
/* Upon Exit: */
/* */
/* Nothing */
/* */
/* -------------------------------------------------------------------- */
VOID HeapFree(HHEAPMEM hHeap, PVOID pv)
{
PHEAPBASE phbase; /* Heap Base Pointer */
PHEAPBASE phbaseStart; /* Heap Base Pointer */
PHEAPBLK phblk; /* Heap Base Pointer */
PHEAPBLK phblkNext; /* Heap Base Pointer */
/* Check to make sure that a valid pointer is */
/* being released */
if ( !hHeap || !pv )
return;
/* Form the address of the subblock housekeeping */
/* record */
phblk = (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
if ( phblk->cbUsed )
{
/* Clear the used component for the subblock */
/* to indicate that it is freed and make sure */
/* that the free list pointer is initialized */
/* as the end of the chain */
phblk->cbUsed = 0UL;
phblk->phblkFree = NULL;
/* Decrement the usage count */
if ( --phblk->phbase->cBlksUsed == 0UL )
{
/* Get the heap base from the heap handle */
phbaseStart = phbase = (PHEAPBASE)hHeap;
/* Move through the heap blocks to try to locate */
/* the block previous to the current block */
while ( phbase )
{
/* See if the next heap base pointer matches the */
/* current heap block base */
if ( phbase->phbaseNext == phblk->phbase )
{
/* Have matched the block pointer, update the */
/* block link to point to the next block after */
/* current block */
phbase->phbaseNext = phblk->phbase->phbaseNext;
/* Check to see if the heap base last block */
/* pointed to the current block that is being */
/* released back to the system and if the case, */
/* update the pointer to the previous block */
if ( phblk->phbase == phbaseStart->phbaseLast )
phbaseStart->phbaseLast = phbase;
/* Release the current memory block back to the */
/* system and return back to the caller */
DosFreeMem((PVOID)phblk->phbase);
return;
}
/* Point to the next block */
phbase = phbase->phbaseNext;
}
}
phbase = phblk->phbase;
/* Check to make sure that the last block */
/* pointer is not the one being added to the */
/* free list chain */
if ( phbase->phblkLast != phblk )
/* Check to see if the free list pointer chain */
/* has been started */
if ( (phblkNext = phbase->phblkFree) != NULL )
{
/* Free list pointer chain exists, find the end */
/* of the chain and add the newly released */
/* block to it */
while ( phblkNext->phblkFree )
phblkNext = phblkNext->phblkFree;
phblkNext->phblkFree = phblk;
}
else
/* No free list pointer chain exists, use the */
/* released block as the starting point */
phbase->phblkFree = phblk;
}
}