home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / except1.zip / HeapMgr.C < prev    next >
C/C++ Source or Header  |  1994-08-23  |  29KB  |  857 lines

  1. #pragma    title("Exception Example  --  Version 1.0 -- (HeapMgr.C)")
  2. #pragma    subtitle("  Memory Manager - Interface Definitions")
  3.  
  4. #pragma    info(noext)
  5.  
  6. #define    INCL_DOS           /* Include OS/2 DOS Kernal        */
  7. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  8.  
  9. #include <os2.h>
  10. #include <stdio.h>
  11.  
  12. #include <memory.h>
  13. #include <string.h>
  14.  
  15. #include "heapmem.h"
  16.  
  17. /* This    module contains    the memory routines used by the    custom        */
  18. /* controls.                                */
  19.  
  20. /* Filename:   HeapMgr.C                        */
  21.  
  22. /*  Version:   3.0                            */
  23. /*  Created:   1994-08-23                        */
  24. /*  Revised:   1994-08-23                        */
  25.  
  26. /* Routines:   HHEAPMEM    HeapAlloc(ULONG    cbInitial, ULONG cbNewBlks);    */
  27. /*           VOID HeapRelease(HHEAPMEM hHeap);            */
  28. /*           ULONG HeapSize(HHEAPMEM hHeap);                */
  29. /*           VOID HeapStatus(HHEAPMEM    hHeap, PULONG pcBlocks,        */
  30. /*                   PULONG pulSize, PULONG pulUsed,        */
  31. /*                   PULONG pulFree, PULONG pulUnused,    */
  32. /*                   PULONG pulOverhead);            */
  33. /*           VOID HeapDisplayStatus(HHEAPMEM hHeap);            */
  34. /*           PVOID HeapMalloc(HHEAPMEM hHeap,    ULONG cbSize);        */
  35. /*           PVOID HeapCalloc(HHEAPMEM hHeap,    ULONG cItems,        */
  36. /*                ULONG cbSize);                */
  37. /*           PVOID HeapRealloc(HHEAPMEM hHeap, PVOID pv,        */
  38. /*                 ULONG cbSize);                */
  39. /*           VOID HeapFree(HHEAPMEM hHeap, PVOID pv);            */
  40.  
  41.  
  42. /* Copyright ╕ 1989-1995  Prominare Inc.  All Rights Reserved.        */
  43.  
  44. /* --------------------------------------------------------------------    */
  45.  
  46. typedef    struct _HEAPBLK
  47.    {
  48.    ULONG          cb;       /* Block Size            */
  49.    ULONG          cbUsed;       /* Used Block Size            */
  50.    struct _HEAPBASE  *phbase;       /* Base Block Pointer        */
  51.    struct _HEAPBLK   *phblkFree;   /* User Memory Pointer        */
  52.    } HEAPBLK ;           /* hblk */
  53.  
  54. typedef    HEAPBLK    *PHEAPBLK;
  55.  
  56. typedef    struct _HEAPBASE
  57.    {
  58.    ULONG         cbInitial;       /* Initial Heap Size            */
  59.    ULONG         cbNewBlks;       /* New Block    Allocation Size        */
  60.    ULONG         cBlksUsed;       /* Blocks Used Count            */
  61.    PHEAPBLK         phblkStart;   /* Starting User Memory Pointer    */
  62.    PHEAPBLK         phblkLast;       /* Starting Free User Memory    Pointer    */
  63.    PHEAPBLK         phblkFree;       /* Starting Free List Memory    Pointer    */
  64.    struct _HEAPBASE *phbaseNext;   /* Next Block Pointer        */
  65.    struct _HEAPBASE *phbaseLast;   /* Last Block Pointer        */
  66.    } HEAPBASE ;           /* hbase */
  67.  
  68. typedef    HEAPBASE *PHEAPBASE;
  69.  
  70. #pragma    subtitle("   Heap Manager - Heap Allocation Function")
  71. #pragma    page( )
  72.  
  73. /* --- HeapAlloc --------------------------------------- [ Public ] ---    */
  74. /*                                    */
  75. /*     This function is    used to    allocate a heap    for the    user using    */
  76. /*     heap start size requested along with the    resizing values.    */
  77. /*     The heap    returns    a handle which is the actual memory address    */
  78. /*     such that the entire heap can be    released quickly.        */
  79. /*                                    */
  80. /*     Upon Entry:                            */
  81. /*                                    */
  82. /*     ULONG cbInitial;    = Initial Heap Size                */
  83. /*     ULONG cbNewBlks;    = New Heap Blocks Size                */
  84. /*                                    */
  85. /*     Upon Exit:                            */
  86. /*                                    */
  87. /*     HeapAlloc = Heap    Handle                        */
  88. /*                                    */
  89. /* --------------------------------------------------------------------    */
  90.  
  91. HHEAPMEM HeapAlloc(ULONG cbInitial, ULONG cbNewBlks)
  92.  
  93. {
  94. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  95.  
  96.                /* Check    to see if the initial heap size    is the    */
  97.                /* default                    */
  98.  
  99. if ( cbInitial == HALLOC_DEFAULT )
  100.    cbInitial = 32768UL;
  101.                /* Check    to see if the initial block size is the    */
  102.                /* default                    */
  103.  
  104. if ( cbNewBlks == HALLOC_DEFAULT )
  105.    cbNewBlks = 32768UL;
  106.                /* Allocate the base memory for the heap    with it    */
  107.                /* being    totally    committed            */
  108.  
  109. if ( DosAllocMem((PPVOID)(PVOID)&phbase, cbInitial, PAG_READ | PAG_WRITE | PAG_COMMIT) )
  110.    return(0UL);
  111.                /* Check    to see if the size requested was not an    */
  112.                /* even page size in which case more memory has    */
  113.                /* been allocated than requested.  In this case,    */
  114.                /* the memory routines will utilize the memory    */
  115.                /* as though it was normally allocated.        */
  116.     
  117. if ( cbInitial % 4096UL    )
  118.    phbase->cbInitial  =    ((cbInitial / 4096UL) +    1UL) * 4096UL;
  119. else
  120.    phbase->cbInitial  =    cbInitial;
  121.  
  122.                /* Check    to see if the new block    size is    not an    */
  123.                /* even page size in which case more memory has    */
  124.                /* been allocated than requested.  In this case,    */
  125.                /* the memory routines will utilize the memory    */
  126.                /* as though it was normally allocated.        */
  127.     
  128. if ( cbNewBlks % 4096UL    )
  129.    phbase->cbNewBlks  =    ((cbNewBlks / 4096UL) +    1UL) * 4096UL;
  130. else
  131.    phbase->cbNewBlks  =    cbNewBlks;
  132.  
  133.                /* Force    the first to have a used block count    */
  134.                /* even though no blocks    have been allocated.    */
  135.                /* By doing this, the first block cannot    be    */
  136.                /* released.                    */
  137. phbase->cBlksUsed = 1UL;
  138.                /* Return the memory address as the handle for    */
  139.                /* the heap                    */
  140.  
  141. return((HHEAPMEM)(phbase->phbaseLast = phbase));
  142. }
  143. #pragma    subtitle("   Heap Manager - Heap Release Function")
  144. #pragma    page( )
  145.  
  146. /* --- HeapRelease ------------------------------------- [ Public ] ---    */
  147. /*                                    */
  148. /*     This function is    used to    release    a heap for the user using    */
  149. /*     the heap    handle that was    returned through the HeapAlloc(    )    */
  150. /*     function.  The routine walks the    heap blocks releasing each    */
  151. /*     block.                                */
  152. /*                                    */
  153. /*     Upon Entry:                            */
  154. /*                                    */
  155. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  156. /*                                    */
  157. /*     Upon Exit:                            */
  158. /*                                    */
  159. /*     Nothing                                */
  160. /*                                    */
  161. /* --------------------------------------------------------------------    */
  162.  
  163. VOID HeapRelease(HHEAPMEM hHeap)
  164.  
  165. {
  166. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  167. PHEAPBASE phbaseNext;           /* Heap Base    Pointer            */
  168.  
  169.                /* Move through the heap    blocks releasing the    */
  170.                /* allocated blocks back    to the system        */
  171. while (    phbase )
  172.    {
  173.    phbaseNext =    phbase->phbaseNext;
  174.    DosFreeMem((PVOID)phbase);
  175.    phbase = phbaseNext;
  176.    }
  177. }
  178.  
  179. #if defined(DEBUG_LISTBOX)
  180.  
  181. #pragma    subtitle("   Heap Manager - Heap Release Function")
  182. #pragma    page( )
  183.  
  184. /* --- HeapSize    ---------------------------------------- [ Public ] ---    */
  185. /*                                    */
  186. /*     This function is    used to    determine the size of the heap.        */
  187. /*                                    */
  188. /*     Upon Entry:                            */
  189. /*                                    */
  190. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  191. /*                                    */
  192. /*     Upon Exit:                            */
  193. /*                                    */
  194. /*     HeapSize    = Size of Heap                        */
  195. /*                                    */
  196. /* --------------------------------------------------------------------    */
  197.  
  198. ULONG HeapSize(HHEAPMEM    hHeap)
  199.  
  200. {
  201. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  202. ULONG      ulSize = 0UL;           /* Heap Size    Holder            */
  203.  
  204.                /* Convert the heap handle to the heap base    */
  205.                /* address                    */
  206.  
  207. phbase = (PHEAPBASE)hHeap;
  208.  
  209.                /* Move through the heap    blocks counting    the    */
  210.                /* allocated blocks size    for the    total memory    */
  211.                /* allocated in the heap                */
  212. while (    phbase )
  213.    {
  214.    ulSize += phbase->cbInitial;
  215.    phbase = phbase->phbaseNext;
  216.    }
  217.                /* Return the allocated size of the heap        */
  218. return(ulSize);
  219. }
  220. #pragma    subtitle("   Heap Manager - Heap Status Function")
  221. #pragma    page( )
  222.  
  223. /* --- HeapStatus -------------------------------------- [ Public ] ---    */
  224. /*                                    */
  225. /*     This function is    used to    determine the status of    the heap by    */
  226. /*     gathering various statistics for    the heap.            */
  227. /*                                    */
  228. /*     Upon Entry:                            */
  229. /*                                    */
  230. /*     HHEAPMEM    hHeap;         = Heap Handle                */
  231. /*     PULONG    pcBlocks;    = Blocks Count Pointer            */
  232. /*     PULONG    pulSize;     = Total Heap Size Pointer            */
  233. /*     PULONG    pulUsed;     = Total Used Pointer            */
  234. /*     PULONG    pulFree;     = Total Free Pointer            */
  235. /*     PULONG    pulUnused;   = Total Unused Pointer            */
  236. /*     PULONG    pulOverhead; = Total Overhead Pointer            */
  237. /*                                    */
  238. /*     Upon Exit:                            */
  239. /*                                    */
  240. /*     Nothing                                */
  241. /*                                    */
  242. /* --------------------------------------------------------------------    */
  243.  
  244. VOID HeapStatus(HHEAPMEM hHeap,    PULONG pcBlocks, PULONG    pulSize,
  245.         PULONG pulUsed,    PULONG pulFree,    PULONG pulUnused, PULONG pulOverhead)
  246.  
  247. {
  248. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  249. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  250.  
  251. *pcBlocks = *pulSize = *pulUsed    = *pulFree = *pulUnused    = *pulOverhead = 0UL;
  252.  
  253.                /* Move through the heap    blocks counting    the    */
  254.                /* allocated blocks size    for the    total memory    */
  255.                /* allocated in the heap                */
  256. while (    phbase )
  257.    {
  258.    ++*pcBlocks;
  259.    *pulSize   += phbase->cbInitial;
  260.    *pulUnused += (phbase->cbInitial - sizeof(HEAPBASE));
  261.    *pulOverhead    += sizeof(HEAPBASE);
  262.    phblk = (PVOID)((PBYTE)phbase + sizeof(HEAPBASE));
  263.  
  264.    while ( (phblk <= phbase->phblkLast)    && phblk->cb )
  265.        {
  266.        if ( phblk->cbUsed )
  267.        {
  268.        *pulUsed += phblk->cb;
  269.        *pulOverhead    += sizeof(HEAPBLK);
  270.        *pulUnused -= (phblk->cb + sizeof(HEAPBLK));
  271.        }
  272.        phblk = (PVOID)((PBYTE)phblk + phblk->cb    + sizeof(HEAPBLK));
  273.        }
  274.    phblk = phbase->phblkFree;
  275.  
  276.    while ( phblk )
  277.        {
  278.        if ( phblk->cb )
  279.        {
  280.        *pulFree += phblk->cb;
  281.        *pulOverhead    += sizeof(HEAPBLK);
  282.        *pulUnused -= (phblk->cb + sizeof(HEAPBLK));
  283.        }
  284.        phblk = phblk->phblkFree;
  285.        }
  286.    phbase = phbase->phbaseNext;
  287.    }
  288. }
  289. #pragma    subtitle("   Heap Manager - Heap Status Function")
  290. #pragma    page( )
  291.  
  292. /* --- HeapDisplayStatus ------------------------------- [ Public ] ---    */
  293. /*                                    */
  294. /*     This function is    used to    display    the status of the heap by    */
  295. /*     gathering various statistics for    the heap.            */
  296. /*                                    */
  297. /*     Upon Entry:                            */
  298. /*                                    */
  299. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  300. /*                                    */
  301. /*     Upon Exit:                            */
  302. /*                                    */
  303. /*     Nothing                                */
  304. /*                                    */
  305. /* --------------------------------------------------------------------    */
  306.  
  307. VOID HeapDisplayStatus(HHEAPMEM    hHeap)
  308.  
  309. {
  310. CHAR  szStrBuf[256];           /* Display Buffer            */
  311. ULONG cBlocks;               /* Blocks Count            */
  312. ULONG ulFree;               /* Free Memory Count            */
  313. ULONG ulOverhead;           /* Overhead Count            */
  314. ULONG ulSize;               /* Total Size Count            */
  315. ULONG ulUnused;               /* Unused Count            */
  316. ULONG ulUsed;               /* Used Count            */
  317.  
  318. if ( hHeap )
  319.    {
  320.    HeapStatus(hHeap, &cBlocks, &ulSize,    &ulUsed, &ulFree, &ulUnused, &ulOverhead);
  321.  
  322.    sprintf(szStrBuf, "Heap Size: %d\nHeap Used: %d (%d%%)\nHeap Free: %d (%d%%)\nHeap Unused: %d (%d%%)\nHeap Overhead: %d (%d%%)",
  323.              ulSize, ulUsed, (ulUsed * 100UL) /    ulSize,    ulFree,    (ulFree    * 100UL) / ulSize,
  324.              ulUnused, (ulUnused * 100UL) / ulSize, ulOverhead,    (ulOverhead * 100UL) / ulSize);
  325.    }
  326. else
  327.    memcpy(szStrBuf, "NULL heap handle.", 18);
  328.  
  329. WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szStrBuf,
  330.           "Heap Debug Status Report", 1UL,
  331.           MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  332. }    
  333.  
  334. #endif
  335.  
  336. #pragma    subtitle("   Heap Manager - Heap Suballocation Function")
  337. #pragma    page( )
  338.  
  339. /* --- HeapMalloc -------------------------------------- [ Public ] ---    */
  340. /*                                    */
  341. /*     This function is    used to    allocate a block of memory from    the    */
  342. /*     heap using the heap handle that was returned through the        */
  343. /*     HeapAlloc( ) function.  The routine walks the heap blocks    */
  344. /*     releasing each looking for either the first free    block        */
  345. /*     that can    accommodate the    request    or the start of    free memory    */
  346. /*     which is    first.    If there is no more memory within the heap    */
  347. /*     block, another block is allocated.  The memory block returned    */
  348. /*     unlike the traditional malloc( )    will be    initialized to 0    */
  349. /*     for all of the memory elements.    The placement of each        */
  350. /*     subblock    is such    that the housekeeping structure    starts on a    */
  351. /*     4 byte boundary.     To achieve this, the memory being requested    */
  352. /*     is padded as required.                        */
  353. /*                                    */
  354. /*     Upon Entry:                            */
  355. /*                                    */
  356. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  357. /*     ULONG    cbSize;    = Memory Size Requested                */
  358. /*                                    */
  359. /*     Upon Exit:                            */
  360. /*                                    */
  361. /*     HeapMalloc =  0 : Error Return, Out of Memory            */
  362. /*          = >0 : Memory    Address                    */
  363. /*                                    */
  364. /* --------------------------------------------------------------------    */
  365.  
  366. PVOID HeapMalloc(HHEAPMEM hHeap, ULONG cbSize)
  367.  
  368. {
  369. PHEAPBASE phbase = (PHEAPBASE)hHeap;   /* Heap Base Pointer        */
  370. PHEAPBASE phbaseNext;           /* Heap Base    Pointer            */
  371. PHEAPBASE phbaseStart;           /* Heap Base    Pointer            */
  372. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  373. PHEAPBLK  phblkPrev;           /* Heap Base    Pointer            */
  374. PHEAPBLK  phblkNext;           /* Heap Base    Pointer            */
  375. ULONG      cbNewBlks;           /* New Block    Size            */
  376. ULONG      cb = (cbSize / 4L + 1L) * 4L;/* Block    Size            */
  377.  
  378.                /* Walk through the base    addresses looking for    */
  379.                /* a subblock of    memory that can    satisfy    the    */
  380.                /* request                    */
  381. while (    phbase )
  382.    {
  383.                /* Get the start    of the free memory subblocks    */
  384.  
  385.    if (    (phblk = phbase->phblkFree) != NULL )
  386.        {
  387.        while ( phblk )
  388.        {
  389.                /* Have found a subblock    not being used,    see if    */
  390.                /* the subblock is large    enough for the request    */
  391.  
  392.        if (    phblk->cb >= cb    )
  393.            {
  394.            if ( phblk->cb >    (cb + sizeof(HEAPBLK)) )
  395.            {
  396.                /* Form the address of the start    of memory    */
  397.                /* subblock by creating the block from the high    */
  398.                /* part of the subblock                */
  399.  
  400.            phblkNext = (PHEAPBLK)((PBYTE)phblk + phblk->cb - cb);
  401.  
  402.                /* Save the amount of memory being used within    */
  403.                /* the subblock                    */
  404.  
  405.            phblkNext->cb     = cb;
  406.            phblkNext->phbase = phbase;
  407.  
  408.                /* Adjust the size of the block allocated from    */
  409.                /* to be    less the size of the block requested    */
  410.                /* and the block    overhead            */
  411.  
  412.            phblk->cb -=    (cb + sizeof(HEAPBLK));
  413.  
  414.                /* Set the current pointer to the new subblock    */
  415.  
  416.            phblk = phblkNext;
  417.            }
  418.            else
  419.                /* No subblock division possible, update    the    */
  420.                /* first    list pointers to exclude the block    */
  421.  
  422.            if (    phblk == phbase->phblkFree )
  423.                phbase->phblkFree = phblk->phblkFree;
  424.            else
  425.                phblkPrev->phblkFree = phblk->phblkFree;
  426.  
  427.                /* Save the requested size in the used portion    */
  428.  
  429.            phblk->cbUsed    = cbSize;
  430.            phblk->phblkFree    = NULL;
  431.            ++phblk->phbase->cBlksUsed;
  432.  
  433.                /* Clear    the block of memory as is the norm and    */
  434.                /* return the address back to the User        */
  435.  
  436.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  437.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  438.            }
  439.                /* Current free list pointer is not adequate for    */
  440.                /* the request, check the next one        */
  441.  
  442.        phblkPrev = phblk;
  443.        phblk = phblkPrev->phblkFree;
  444.        }
  445.        }
  446.                /* Check    to see if the last block has been    */
  447.                /* defined for the current memory block        */
  448.  
  449.    if (    phbase->phblkLast )
  450.        {
  451.                /* Check    to see if the last block of the    current    */
  452.                /* memory block has been    released in which case    */
  453.                /* it would not have been added to the free list    */
  454.                /* chain    since the last block would then    have    */
  455.                /* been undefined                */
  456.  
  457.        if ( phbase->phblkLast->cbUsed == 0UL )
  458.        {
  459.                /* Last block of    the current memory block    */
  460.                /* is a free block, check to see    if the block    */
  461.                /* can be sub-divided                */
  462.  
  463.        if (    phbase->phblkLast->cb >= cb )
  464.            {
  465.            phblk = phbase->phblkLast;
  466.  
  467.                /* See if the block is dividable            */
  468.  
  469.            if ( phbase->phblkLast->cb > (cb    + sizeof(HEAPBLK)) )
  470.            {
  471.                /* Form the address of the start    of memory    */
  472.                /* subblock by creating the block from the high    */
  473.                /* part of the subblock                */
  474.  
  475.            phblkNext = (PHEAPBLK)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) + cb);
  476.  
  477.                /* Update the next last block pointer to    take    */
  478.                /* into consideration the new block being    */
  479.                /* allocated                    */
  480.  
  481.            phblkNext->phbase    = phbase;
  482.            phblkNext->cb    = phbase->phblkLast->cb    - (cb +    sizeof(HEAPBLK));
  483.            phblkNext->cbUsed    = 0UL;
  484.            phblkNext->phblkFree    = NULL;
  485.  
  486.                /* Update the last block    pointer    to point to the    */
  487.                /* next block created from the larger block    */
  488.  
  489.            phbase->phblkLast = phblkNext;
  490.  
  491.                /* Save the amount of memory being used within    */
  492.                /* the subblock                    */
  493.  
  494.            phblk->cb     = cb;
  495.            }
  496.                /* Save the requested size in the used portion    */
  497.  
  498.            phblk->cbUsed    = cbSize;
  499.            phblk->phblkFree    = NULL;
  500.            ++phblk->phbase->cBlksUsed;
  501.  
  502.                /* Clear    the block of memory as is the norm and    */
  503.                /* return the address back to the User        */
  504.  
  505.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  506.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  507.            }
  508.        }
  509.        else
  510.                /* Check    to see if no free subblocks found, in    */
  511.                /* which    case a new subblock needs to be    added    */
  512.                /* after    the last current subblock        */
  513.  
  514.        if (    (((PBYTE)phbase->phblkLast + (sizeof(HEAPBLK) *    2L) + phbase->phblkLast->cb) + cb) <
  515.          ((PBYTE)phbase    + phbase->cbInitial) )
  516.            {
  517.                /* Using    the address of the last    subblock,    */
  518.                /* calculate the    address    of the new subblock    */
  519.                /* such that it is just after the block of    */
  520.                /* memory being used by the User            */
  521.  
  522.            phbase->phblkLast = phblk = (PVOID)((PBYTE)phbase->phblkLast + sizeof(HEAPBLK) +    phbase->phblkLast->cb);
  523.  
  524.                /* Subblock is adequate for the memory request,    */
  525.                /* save the requested size in the used portion    */
  526.  
  527.            phblk->cb    = cb;
  528.            phblk->cbUsed    = cbSize;
  529.  
  530.                /* Save the base    of the memory block to allow    */
  531.                /* easy compaction of free memory blocks    when    */
  532.                /* memory is released                */
  533.  
  534.            phblk->phbase    = phbase;
  535.            ++phblk->phbase->cBlksUsed;
  536.  
  537.                /* Clear    the block of memory as is the norm and    */
  538.                /* return the address back to the User        */
  539.  
  540.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  541.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  542.            }
  543.        }
  544.        else
  545.        if (    (phbase->cbInitial - sizeof(HEAPBASE) -    sizeof(HEAPBLK)) > cb )
  546.            {
  547.                /* No subblocks created yet, start the first    */
  548.                /* subblock after the base housekeeping area    */
  549.  
  550.            phbase->phblkLast = phblk = phbase->phblkStart =    (PVOID)((PBYTE)phbase +    sizeof(HEAPBASE));
  551.  
  552.                /* Save the requested size in the used portion    */
  553.  
  554.            phblk->cb    = cb;
  555.            phblk->cbUsed    = cbSize;
  556.  
  557.                /* Save the base    of the memory block to allow    */
  558.                /* easy compaction of free memory blocks    when    */
  559.                /* memory is released                */
  560.  
  561.            phblk->phbase    = phbase;
  562.            ++phblk->phbase->cBlksUsed;
  563.  
  564.                /* Clear    the block of memory as is the norm and    */
  565.                /* return the address back to the User        */
  566.  
  567.            memset((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)), 0, cbSize);
  568.            return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  569.            }
  570.  
  571.    phbase = phbase->phbaseNext;
  572.    }
  573.                /* Convert the heap handle to the heap base    */
  574.                /* address                    */
  575.  
  576. phbaseStart = (PHEAPBASE)hHeap;
  577.  
  578.                /* Point    to the next memory block        */
  579.  
  580. phbase = phbaseStart->phbaseLast;
  581.  
  582.                /* Last block found, check to see if the    amount    */
  583.                /* of memory requested is larger    than the new    */
  584.                /* block    size in    which case the full block is    */
  585.                /* allocated                    */
  586.  
  587. if ( cb    > (phbaseStart->cbNewBlks - sizeof(HEAPBASE) - sizeof(HEAPBLK))    )
  588.  
  589.                /* Size of memory requested larger than the    */
  590.                /* block    size, calculate    the amount of memory    */
  591.                /* needed including the housekeeping records    */
  592.  
  593.    cbNewBlks = cb + sizeof(HEAPBASE) + sizeof(HEAPBLK);
  594. else
  595.    cbNewBlks = phbaseStart->cbNewBlks;
  596.  
  597.                /* Allocate the necessary memory            */
  598.  
  599. if ( DosAllocMem((PPVOID)(PVOID)&phbaseNext, cbNewBlks,    PAG_READ | PAG_WRITE | PAG_COMMIT) )
  600.  
  601.                /* Error    in allocating the memory, return NULL    */
  602.                /* to indicate no memory    was allocated        */
  603.    return(NULL);
  604. else
  605.                /* Save the new block address in    the last block    */
  606.                /* next pointer                    */
  607.  
  608.    phbase->phbaseNext =    phbaseStart->phbaseLast    = phbaseNext;
  609.  
  610.                /* Check    to see if the new block    size is    not an    */
  611.                /* even page size in which case more memory has    */
  612.                /* been allocated than requested.  In this case,    */
  613.                /* the memory routines will utilize the memory    */
  614.                /* as though it was normally allocated.        */
  615.     
  616. if ( (phbaseNext->cbNewBlks = cbNewBlks) % 4096UL )
  617.    phbaseNext->cbInitial  = ((cbNewBlks    / 4096UL) + 1) * 4096UL;
  618. else
  619.    phbaseNext->cbInitial  = cbNewBlks;
  620.  
  621.                /* Form the address of the start    of memory    */
  622.                /* subblock                    */
  623.  
  624. phbaseNext->phblkLast =    phblk =    phbaseNext->phblkStart = (PVOID)((PBYTE)phbaseNext + sizeof(HEAPBASE));
  625.  
  626.                /* Save the amount of memory being used within    */
  627.                /* the subblock                    */
  628. phblk->cb     =    cb;
  629. phblk->cbUsed =    cbSize;
  630.                /* Save the base    of the memory block to allow    */
  631.                /* easy compaction of free memory blocks    when    */
  632.                /* memory is released                */
  633.  
  634. phblk->phbase     = phbaseNext;
  635. ++phblk->phbase->cBlksUsed;
  636.  
  637.                /* Return the address of    the User memory    block    */
  638.  
  639. return((PVOID)((PBYTE)phblk + sizeof(HEAPBLK)));
  640. }
  641. #pragma    subtitle("   Heap Manager - Heap Suballocation Function")
  642. #pragma    page( )
  643.  
  644. /* --- HeapCalloc -------------------------------------- [ Public ] ---    */
  645. /*                                    */
  646. /*     This function is    used to    release    a heap for the user using    */
  647. /*     the heap    handle that was    returned through the HeapAlloc(    )    */
  648. /*     function.  The routine uses the HeapMalloc( ) since it is    */
  649. /*     designed    to clear the memory allocated like a normal        */
  650. /*     calloc( ) function.                        */
  651. /*                                    */
  652. /*     Upon Entry:                            */
  653. /*                                    */
  654. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  655. /*     ULONG    cItems;    = Items    Count                    */
  656. /*     ULONG    cbSize;    = Item Size                    */
  657. /*                                    */
  658. /*     Upon Exit:                            */
  659. /*                                    */
  660. /*     HeapCalloc =  0 : Error Return, Out of Memory            */
  661. /*          = >0 : Memory    Address                    */
  662. /*                                    */
  663. /* --------------------------------------------------------------------    */
  664.  
  665. PVOID HeapCalloc(HHEAPMEM hHeap, ULONG cItems, ULONG cbSize)
  666.  
  667. {
  668. return(HeapMalloc(hHeap, cItems    * cbSize));
  669. }
  670. #pragma    subtitle("   Heap Manager - Heap Re-allocation Function")
  671. #pragma    page( )
  672.  
  673. /* --- HeapRealloc ------------------------------------- [ Public ] ---    */
  674. /*                                    */
  675. /*     This function is    used to    reallocate a block of memory for the    */
  676. /*     user.  If the block is smaller, the same    memory is returned    */
  677. /*     otherwise a new block is    returned and the old block released.    */
  678. /*                                    */
  679. /*     Upon Entry:                            */
  680. /*                                    */
  681. /*     HHEAPMEM    hHeap;    = Heap Handle                    */
  682. /*     PVOID    pv;    = Current Memory Block Address            */
  683. /*     ULONG    cbSize;    = Required Memory Size                */
  684. /*                                    */
  685. /*     Upon Exit:                            */
  686. /*                                    */
  687. /*     HeapRealloc =  0    : Error    Return,    Out of Memory            */
  688. /*           = >0    : Memory Address                */
  689. /*                                    */
  690. /* --------------------------------------------------------------------    */
  691.  
  692. PVOID HeapRealloc(HHEAPMEM hHeap, PVOID    pv, ULONG cbSize)
  693.  
  694. {
  695. PVOID      pvNew;           /* New Memory Block Address        */
  696. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  697.  
  698.                /* Check    to make    sure that the pointer is not    */
  699.                /* NULL which would cause a GP            */
  700. if ( pv    == NULL    )
  701.    return(NULL);
  702.                /* Form the address of the subblock housekeeping    */
  703.                /* record                    */
  704.  
  705. phblk =    (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
  706.  
  707.                /* Determine if the size    requested is smaller    */
  708.                /* than the current block size in which case the    */
  709.                /* the block size should    be used    and returned    */
  710.  
  711. if ( phblk->cb >= cbSize )
  712.    {
  713.    phblk->cbUsed = cbSize;
  714.    return(pv);
  715.    }
  716. else
  717.                /* New size larger than current block size,    */
  718.                /* allocate a new block                */
  719.  
  720.    if (    (pvNew = HeapMalloc(hHeap, cbSize)) != NULL )
  721.        {
  722.                /* Transfer the memory from the old block to the    */
  723.                /* new block                    */
  724.  
  725.        memmove(pvNew, pv, phblk->cbUsed);
  726.  
  727.                /* Release the memory block for the old block    */
  728.  
  729.        HeapFree(hHeap, pv);
  730.  
  731.                /* Return the address of    the new    block        */
  732.        return(pvNew);
  733.        }
  734.    else
  735.                /* Error    occurred during    the memory allocation,    */
  736.                /* return NULL to indicate problem        */
  737.        return(NULL);
  738. }
  739. #pragma    subtitle("   Heap Manager - Heap Release Function")
  740. #pragma    page( )
  741.  
  742. /* --- HeapFree    ---------------------------------------- [ Public ] ---    */
  743. /*                                    */
  744. /*     This function is    used to    release    a block    of memory that has    */
  745. /*     been allocated by the user.  The    routine    performs free block    */
  746. /*     compaction to allow for proper reallocation of unused blocks.    */
  747. /*                                    */
  748. /*     Upon Entry:                            */
  749. /*                                    */
  750. /*     HHEAPMEM    hHeap; = Heap Handle                    */
  751. /*     PVOID    pv;    = Address of User Memory    to Release        */
  752. /*                                    */
  753. /*     Upon Exit:                            */
  754. /*                                    */
  755. /*     Nothing                                */
  756. /*                                    */
  757. /* --------------------------------------------------------------------    */
  758.  
  759. VOID HeapFree(HHEAPMEM hHeap, PVOID pv)
  760.  
  761. {
  762. PHEAPBASE phbase;           /* Heap Base    Pointer            */
  763. PHEAPBASE phbaseStart;           /* Heap Base    Pointer            */
  764. PHEAPBLK  phblk;           /* Heap Base    Pointer            */
  765. PHEAPBLK  phblkNext;           /* Heap Base    Pointer            */
  766.  
  767.                /* Check    to make    sure that a valid pointer is    */
  768.                /* being    released                */
  769. if ( !hHeap || !pv )
  770.    return;
  771.                /* Form the address of the subblock housekeeping    */
  772.                /* record                    */
  773.  
  774. phblk =    (PHEAPBLK)((PBYTE)pv - sizeof(HEAPBLK));
  775.  
  776. if ( phblk->cbUsed )
  777.    {
  778.                /* Clear    the used component for the subblock    */
  779.                /* to indicate that it is freed and make    sure    */
  780.                /* that the free    list pointer is    initialized    */
  781.                /* as the end of    the chain            */
  782.  
  783.    phblk->cbUsed    = 0UL;
  784.    phblk->phblkFree = NULL;
  785.  
  786.                /* Decrement the    usage count            */
  787.  
  788.    if (    --phblk->phbase->cBlksUsed == 0UL )
  789.        {
  790.                /* Get the heap base from the heap handle    */
  791.  
  792.        phbaseStart = phbase = (PHEAPBASE)hHeap;
  793.  
  794.                /* Move through the heap    blocks to try to locate    */
  795.                /* the block previous to    the current block    */
  796.        while ( phbase  )
  797.        {
  798.                /* See if the next heap base pointer matches the    */
  799.                /* current heap block base            */
  800.  
  801.        if (    phbase->phbaseNext == phblk->phbase )
  802.            {
  803.                /* Have matched the block pointer, update the    */
  804.                /* block    link to    point to the next block    after    */
  805.                /* current block                    */
  806.  
  807.            phbase->phbaseNext = phblk->phbase->phbaseNext;
  808.  
  809.                /* Check    to see if the heap base    last block    */
  810.                /* pointed to the current block that is being    */
  811.                /* released back    to the system and if the case,    */
  812.                /* update the pointer to    the previous block    */
  813.  
  814.            if ( phblk->phbase == phbaseStart->phbaseLast )
  815.            phbaseStart->phbaseLast = phbase;
  816.  
  817.                /* Release the current memory block back    to the    */
  818.                /* system and return back to the    caller        */
  819.  
  820.            DosFreeMem((PVOID)phblk->phbase);
  821.            return;
  822.            }
  823.                /* Point    to the next block            */
  824.  
  825.        phbase = phbase->phbaseNext;
  826.        }
  827.        }
  828.    phbase = phblk->phbase;
  829.  
  830.                /* Check    to make    sure that the last block    */
  831.                /* pointer is not the one being added to    the    */
  832.                /* free list chain                */
  833.  
  834.    if (    phbase->phblkLast != phblk )
  835.  
  836.                /* Check    to see if the free list    pointer    chain    */
  837.                /* has been started                */
  838.  
  839.        if ( (phblkNext = phbase->phblkFree) != NULL )
  840.        {
  841.                /* Free list pointer chain exists, find the end    */
  842.                /* of the chain and add the newly released    */
  843.                /* block    to it                    */
  844.  
  845.        while ( phblkNext->phblkFree    )
  846.            phblkNext = phblkNext->phblkFree;
  847.  
  848.        phblkNext->phblkFree    = phblk;
  849.        }
  850.        else
  851.                /* No free list pointer chain exists, use the    */
  852.                /* released block as the    starting point        */
  853.  
  854.        phbase->phblkFree = phblk;
  855.    }
  856. }
  857.