home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / audiopdd.zip / malloc.c < prev    next >
C/C++ Source or Header  |  1999-02-19  |  20KB  |  571 lines

  1. //
  2. // malloc.c
  3. // 25-Jan-99
  4. //
  5. // static void dumpheap(void);
  6. // static void SignatureCheck ( PMEMBLOCK p, PSZ idText );
  7. // static void HeapCheck ( PSZ idText );
  8. // static PMEMBLOCK make_new_free(PMEMBLOCK pmbOldFree, unsigned uRequest);
  9. // static unsigned _msize(void __near *pvBlock);
  10. // static void __near * npvAllocateBlock( PMEMBLOCK pmb, USHORT uRequest, PMEMBLOCK pmbPrev );
  11. // static void remove(PMEMBLOCK pmb);
  12. // static void compact(void);
  13. // void __near *malloc( unsigned uSize );
  14. // void free(void __near *pvBlock);
  15. // unsigned _memfree(void);
  16. // void __near *realloc(void __near *pvBlock, unsigned usLength);
  17. // unsigned HeapInit(unsigned uSize);
  18.  
  19. #include "cs40.h"
  20.  
  21. #define HEMP_DBG 1
  22.  
  23. // putting this in class BSS means won't blowout file size and extra HEAP_SIZE bytes!
  24. // as it does if using the original  #pragma data_seg ("_HEMP","ENDDS");
  25.  
  26. #pragma data_seg ("_HEMP");     // yes, _HEMP
  27.  
  28. #define DEFAULT_HEAP 4096
  29. #define HEAP_SIZE    8192 // max heap size
  30. //#define SIGNATURE    0xBEEFDEAD  // "DEADBEEF" when view in hex in word order.
  31. #define SIGNATURE  0x3477ADDE  // 'DEAD7734' in ascii view
  32.  
  33. typedef struct _MEMBLOCK {
  34.    unsigned long ulSignature;
  35.    unsigned uSize;
  36.    struct _MEMBLOCK *pmbNext;
  37.    char achBlock[1];
  38. } MEMBLOCK, __near *PMEMBLOCK;
  39.  
  40. #define HDR_SIZE  ( sizeof(MEMBLOCK) - 1 )
  41.  
  42. // We won't leave a hole in memory any smaller than MIN_FragSize.
  43. #define MIN_FragSize  4
  44.  
  45. //--- Global Variables used to manage the heap:
  46. // (no reason to be extern globals, so making them static, 26-Jan-99)
  47.  
  48. static PMEMBLOCK pmbUsed=0;    // Points to head of list of allocated memory blocks.
  49.                         // Newly allocated blocks are inserted into head of list.
  50. static PMEMBLOCK pmbFree;      // Points to head of list of available memory blocks.
  51. static unsigned uMemFree;      // N bytes available for allocation.
  52.  
  53. static USHORT fMemoryDoc = 0;
  54. static USHORT nAlloc = 0;           // Current number of allocated blocks.
  55. static USHORT cAlloc = 0;           // Total memory in allocated blocks incl. headers.
  56. static USHORT nAllocCalls = 0;      // Cumulative total, number of malloc() calls.
  57. static USHORT nFree  = 0;           // Current number of free blocks.
  58. static USHORT cFree  = 0;           // Total memory in free blocks incl. headers.
  59. static USHORT nFreeCalls  = 0;      // Cumulative total, number of free() calls.
  60. static USHORT nCompact = 0;         // Num of times we've joined two adjacent free blocks into a single larger block
  61. static USHORT cTotalHeap = HEAP_SIZE;
  62.  
  63. static char __near acHeap[HEAP_SIZE];
  64.                         // The heap.  NOTE:  This must be the last data definition in the HEAP segment,
  65.                         // although not done currently, we are planning to size the heap down at INIT
  66.                         // time.  If this is done, any vbls in the HEAP segment that
  67.                         // appear after the HEAP would become unaddressable.
  68.  
  69. #ifdef HEMP_DBG
  70.  
  71. //--- Heap methods:
  72.  
  73. //static void dumpheap(void)
  74. void dumpheap(void)
  75. {
  76.    int i;
  77.    PMEMBLOCK pmb;
  78.    unsigned u=0;
  79.  
  80.    pmb=pmbUsed;
  81.    ddprintf("~HEAP: Heap Dump - Used blocks\n");
  82.    for (i=0; i<32; i++) {
  83.       if (!pmb) break;
  84.       ddprintf("~  pmb=%p, btyes=%u\n",(void __far *) pmb, pmb->uSize);
  85.       u+=pmb->uSize;
  86.       pmb=pmb->pmbNext;
  87.    }
  88.    ddprintf("~  Total used = %u\n",u);
  89.  
  90.    u=0;
  91.    pmb=pmbFree;
  92.    ddprintf("~HEAP: Heap Dump - Free blocks\n");
  93.    for (i=0; i<32; i++) {
  94.       if (!pmb) break;
  95.       ddprintf("~  pmb=%p, bytes=%u\n",(void __far *) pmb, pmb->uSize);
  96.       u+=pmb->uSize;
  97.       pmb=pmb->pmbNext;
  98.    }
  99.    ddprintf("~  Total free = %u\n",u);
  100.  
  101.    ddprintf("~ alloc:currblks=%u, calls=%u;  free:currblks=%u, calls=%u\n",
  102.               nAlloc,nAllocCalls,nFree,nFreeCalls);
  103. }
  104.  
  105. #endif
  106.  
  107.  
  108. static void SignatureCheck ( PMEMBLOCK p, PSZ idText )
  109. {
  110.  
  111.    bool bGoodPointer;
  112.  
  113.    // Set bGoodPointer to indicate whether or not 'p' points within heap.
  114.    bGoodPointer = (((USHORT) p) >= ((USHORT) acHeap))
  115.                   && (((USHORT) p) <= (((USHORT) acHeap) + HEAP_SIZE)) ;
  116.                               //### heap might have less than HEAP_SIZE bytes
  117.  
  118.    // Check for correct signature.
  119.    if (bGoodPointer)
  120.       bGoodPointer = (p->ulSignature == SIGNATURE);
  121.  
  122.    if (! bGoodPointer)
  123.    {
  124. #ifdef HEMP_DBG
  125.       ddprintf( "~Heap pointer out of range, or signature exception: %p %s\n", p, idText );
  126. #endif
  127.       int3();
  128.    }
  129.  return;
  130.  idText;
  131. }
  132.  
  133. static void HeapCheck ( PSZ idText )
  134. {
  135.    PMEMBLOCK p;
  136.    for ( nAlloc = 0, cAlloc = 0, p = pmbUsed; p; p = p->pmbNext ) {
  137.       ++nAlloc;
  138.       cAlloc += p->uSize + HDR_SIZE;
  139.       //SignatureCheck( p,(PSZ) "HeapCheck() Used list" );
  140.       //SignatureCheck( p,(PSZ)0);
  141.       SignatureCheck( p,(PSZ)"HCUL");
  142.    }
  143.    for ( nFree = 0, cFree = 0, p = pmbFree; p; p = p->pmbNext ) {
  144.       ++nFree;
  145.       cFree += p->uSize + HDR_SIZE;
  146.       //SignatureCheck( p,(PSZ) "HeapCheck() Free list" );
  147.       //SignatureCheck( p,(PSZ)0);
  148.       SignatureCheck( p,(PSZ)"HCFL");
  149.    }
  150.    if (fMemoryDoc & 1) {
  151.       if (cAlloc + cFree != cTotalHeap) {
  152. #ifdef HEMP_DBG
  153.          ddprintf( "~Heap Alloc + Free != Total\n" );
  154.          dumpheap();
  155. #endif
  156.          int3();
  157.       }
  158.    }
  159.  return;
  160.  idText;
  161. }
  162.  
  163.  
  164.  
  165. // Threshold for creating a new free block.
  166. #define  MIN_Leftover  (HDR_SIZE + MIN_FragSize)
  167.  
  168. /* make_new_free()
  169.    Formats the back part of an existing free MEMBLOCK as a new, smaller
  170.    "Free" MEMBLOCK.  Doesn't update Global vbls (caller responsibility).
  171.       IN:   pmbOldFree - pointer to existing memory block.
  172.             uSize - offset, which won't be included in new allocation.
  173.                     it's assumed HDR is not included in uSize.
  174.       OUT:  pointer to new free MEMBLOCK, is  a new block of free memory,
  175.             is created at pmbOldFree + uRequest.  The memory block header
  176.             in both the new block and the old block are properly initialized
  177.             on return, but we don't update the Free list or Allocated list.
  178.       OUT:  NULL if the new free memory block is smaller than the
  179.             framentation threshold.
  180.  
  181. The fragmentation consideration comes into play when we find a block that's
  182. big enough to hold the requested memory, but not big enough for the leftover
  183. part to be useful as another free block.
  184.  
  185.     _______________________free block_______________________________________
  186.    |  free    |                                                             |
  187.    |  block   |       space available                                       |
  188.    |  header  |          (pmbFree->uSize bytes long)                        |
  189.    |(HDR_SIZE |                                                             |
  190.    |__bytes)__|_____________________________________________________________|
  191.  
  192.    <-- HDR --> <------------------------- l -------------------------------->
  193.  
  194. Must either be allocated in total, or must become:
  195.  
  196.     _______________________used block_______________________________________
  197.    |  used    |                                     |  free    |            |
  198.    |  block   |  space allocated                    |  block   | space      |
  199.    |  header  |  == uSize (following DWORD align't) |  header  | available  |
  200.    |(HDR_SIZE |     (pmbUsed->uSize bytes long)     |(HDR_SIZE |            |
  201.    |__bytes)__|_____________________________________|__bytes)__|____________|
  202.  
  203.    <-- HDR --> <-------------- n ------------------><-- HDR --> <--- m ----->
  204.  
  205. To be split into an allocated and a new, smaller free block, 'm' must be at
  206. least MIN_FragSize bytes long.
  207.  
  208. Everything should remain 4 byte aligned since the HDR_SIZE, MIN_FragSize,
  209. and the space allocated (after we munge it) are all multiples of 4.
  210.  
  211. This means that in order for a free block to be chosen, one of the following
  212. equation must hold
  213.  
  214.   Case 1:  n  <=  l  < (n + HDR + MIN_FragSize)
  215.   Here, we'll allocate the entire block.  This makes the block somewhat
  216.   larger than the request, but prevents some degree of fragmentation.
  217.  
  218.   Case 2:  (n + HDR + MIN_FragSize) <= l
  219.   We split the block into an allocated part to satisfy the allocation request,
  220.   and a free block which can be allocated in a subsequent request.
  221. */
  222.  
  223. static PMEMBLOCK make_new_free(PMEMBLOCK pmbOldFree, unsigned uRequest)
  224. {
  225.    PMEMBLOCK pmbNewFree;     // If we create a new free block, it goes here.
  226.  
  227.    // Which of the two cases (as described in function header) have we got?
  228.    // We know we're big enough to satisfy request, is there enough leftover
  229.    // for a new free block?
  230.  
  231.     if ((uRequest + MIN_Leftover) > pmbOldFree->uSize) {
  232.        // Not enough leftover, allocate the entire free block.  Don't
  233.        // change pmbOldFree->uSize.
  234.        pmbNewFree = 0;
  235.     }
  236.     else {
  237.        // We've got enough leftover to make a new free block.
  238.        pmbNewFree = (PMEMBLOCK) ((char __near *) pmbOldFree + HDR_SIZE + uRequest );
  239.        pmbNewFree->ulSignature = SIGNATURE;
  240.        pmbNewFree->uSize = pmbOldFree->uSize - (uRequest + HDR_SIZE);
  241.        pmbNewFree->pmbNext = pmbOldFree->pmbNext;
  242.  
  243.        // Update the size of the free block that was passed in.
  244.        pmbOldFree->uSize -= (pmbNewFree->uSize + HDR_SIZE);
  245.     }
  246.  
  247.    return pmbNewFree;
  248. }
  249.  
  250.  
  251. /**@internal _msize
  252.  */
  253. static unsigned _msize(void __near *pvBlock)
  254. {
  255.    PMEMBLOCK pmb;
  256.  
  257.    if (!pvBlock)
  258.       return 0;
  259.  
  260.    pmb = (PMEMBLOCK) ((char __near *) pvBlock - HDR_SIZE);
  261.  
  262.    return pmb->uSize;
  263. }
  264.  
  265.  
  266. /**@internal pmbAllocateBlock
  267.  *  Update all data structures for allocation of one memory block.  It's
  268.  *  assumed, on entry, that the block is large enough for the requested
  269.  *  allocation.
  270.  * @param PMEMBLOCK pmb - the current memory block on the Free list to
  271.  *  allocate.
  272.  * @param USHORT uRequest - size of the memory request to fill, not counting
  273.  *  memory block header.
  274.  * @param PMEMBLOCK pmbPrev - the memory block which precedes the block being
  275.  *  allocated in the Free list.  NULL if no predecessor (ie, pmb is pointed to
  276.  *  by ::pmbFree).
  277.  * @return PMEMBLOCK - pointer to the data part of the allocated memory block,
  278.  *  suitable for return to malloc() caller.
  279.  */
  280. static void __near *
  281. npvAllocateBlock( PMEMBLOCK pmb, USHORT uRequest, PMEMBLOCK pmbPrev )
  282. {
  283.    //pmb points to the selected block.
  284.    //pmbPrev points to the block prior to the selected block, NULL if pmbFree.
  285.    PMEMBLOCK pmbOldNext;            // Original free block that follows the block being allocated.
  286.    PMEMBLOCK pmbNewFree;            // Leftover free memory from the allocated block.
  287.  
  288.    // Split this block into an allocated + free part if it's big enough.
  289.    pmbNewFree = make_new_free( pmb, uRequest );
  290.  
  291.    // Update global memory counter.
  292.    uMemFree -= (pmb->uSize + HDR_SIZE);
  293.  
  294.    // Add this block into the front of the Allocated list.
  295.    pmbOldNext = pmb->pmbNext;
  296.    pmb->pmbNext = pmbUsed;
  297.    pmbUsed = pmb;
  298.  
  299.    // Remove the new allocation from the Free list.
  300.    if (pmbNewFree) {                // If we split off a new free block
  301.       pmbNewFree->pmbNext = pmbOldNext;
  302.       if (pmbPrev)                  // If we're not at head of Free list
  303.          pmbPrev->pmbNext = pmbNewFree;
  304.       else
  305.          pmbFree = pmbNewFree;
  306.    }
  307.    else {                           // We allocated the entire free block.
  308.       if (pmbPrev)                  // If we're not at head of Free list
  309.          pmbPrev->pmbNext = pmbOldNext;
  310.       else
  311.          pmbFree = pmbOldNext;
  312.    }
  313.  
  314.    return (void __near *) pmb->achBlock;
  315. }
  316.  
  317.  
  318. /* malloc()
  319. This function searches the list of free blocks until it finds one big enough
  320. to hold the amount of memory requested, which is passed in uSize.  The uSize
  321. request is sized up for:
  322.   - a memory block header
  323.   - four byte alignment
  324.   - minimum fragmentation
  325.  
  326. See helper function make_new_free() for discussion of fragmentation handling.
  327. */
  328.  
  329. void __near *malloc( unsigned uSize )
  330. {
  331.    USHORT uRequest;                    // Request size after alignment.
  332.    PMEMBLOCK pmb, pmbPrev;             // Use to walk free lists.
  333.    void __near *npvReturn = 0;         // Return value.
  334.  
  335.    ++nAllocCalls;                      // Diagnostics.
  336.    //HeapCheck((PSZ) "malloc() entry" );
  337.    //HeapCheck((PSZ)0);
  338.    HeapCheck((PSZ)"MEXX");
  339.  
  340.    if (! uSize) return 0;
  341.  
  342.    uRequest = (uSize + 3) & -4;        // Force DWORD alignment.
  343.  
  344.    if (pmbFree->uSize >= uRequest)
  345.       npvReturn = npvAllocateBlock( pmbFree, uRequest, NULL );
  346.    else {
  347.       pmbPrev = pmbFree;
  348.       for ( pmb=pmbFree->pmbNext; pmb; pmbPrev=pmb, pmb=pmb->pmbNext)
  349.          if (pmb->uSize >= uRequest) {
  350.             npvReturn = npvAllocateBlock( pmb, uRequest, pmbPrev );
  351.             break;
  352.          }
  353.    }
  354.  
  355.    if (npvReturn)
  356.       //SignatureCheck( (PMEMBLOCK) (((PUCHAR) npvReturn) - HDR_SIZE), (PSZ) "malloc() exit, allocated block" );
  357.       //SignatureCheck( (PMEMBLOCK) (((PUCHAR) npvReturn) - HDR_SIZE), (PSZ)0);
  358.       SignatureCheck( (PMEMBLOCK) (((PUCHAR) npvReturn) - HDR_SIZE), (PSZ)"MEAB");
  359.    else {
  360.       // Out of Memory !!!
  361. //    pError->vLog( HEAP_Err_NoMemory, (USHORT) uSize );
  362.  
  363. #ifdef HEMP_DBG
  364.       ddprintf("~Out of memory, dumpheap()...\n");
  365.       dumpheap();
  366. #endif
  367.       int3();
  368.    }
  369.  
  370.    //HeapCheck((PSZ) "malloc() exit" );
  371.    //HeapCheck((PSZ)0);
  372.    HeapCheck((PSZ)"MXXX");
  373.    return npvReturn;
  374. }
  375.  
  376. /* void compact(void)
  377. This function compacts the free blocks together.  This function is a
  378. companion to free(), and thus the algorithm is tailored to how free()
  379. works.  Change the algorithm in free(), and you'll have to change this
  380. function too.
  381.  
  382. When free() frees a block, it sets the head of the free list, pmbFree, to
  383. point to it.  Then the newly freed block points to whatever the old pmbFree
  384. pointed to.  In other words, each new free block is added to the head of
  385. the free list.
  386.  
  387. If compact() is always called after a block is freed, then it can be
  388. guaranteed that the free list is always compacted (i.e. you won't find
  389. two adjacent free blocks anywhere in the heap) _before_ each call to free().
  390. Therefore, the newly freed block can be located in only one of the
  391. following positions:
  392. 1. Not adjacent to any other free blocks (compacting not necessary)
  393. 2. Physically before another free block
  394. 3. Physically after another free block
  395. 4. Between two free blocks (i.e. the block occupies the entire space
  396.    between two free blocks)
  397.  
  398. Since the newly freed block is the first in the free list, compact()
  399. starts with the second block in the list (i.e. pmbFree->pmbNext).
  400. Each free block is then compared with the newly freed block for
  401. adjacency.  If a given block is located before the new block, then it
  402. can't possibly be also located after, and vice versa.  Hence, the
  403. "else if" statement in the middle of the loop.
  404.  
  405. Also, the newly freed block can only be adjacent to at most two other
  406. blocks.  Therefore, the operation of combining two adjacent free blocks can
  407. only happen at most twice.  The variable nFreed counts the number of times
  408. two blocks are combined.  The function exits if nFreed reaches two.  nFreed
  409. is initially 0.
  410.  
  411. Helper macro after() takes a PMEMBLOCK (call it pmb) as a parameter,
  412. and calculates where an adjacent free block would exist if it were
  413. physically located after pmb.
  414.  
  415. Helper function remove() removes an element from the free list.
  416. */
  417.  
  418. #define after(pmb) ((PMEMBLOCK) ((char __near *) pmb + pmb->uSize + HDR_SIZE))
  419.  
  420. static void remove(PMEMBLOCK pmb)
  421. {
  422.    PMEMBLOCK pmbPrev;
  423.  
  424.    if (pmb == pmbFree) {
  425.       pmbFree = pmbFree->pmbNext;
  426.       return;
  427.    }
  428.  
  429.    for (pmbPrev=pmbFree; pmbPrev; pmbPrev=pmbPrev->pmbNext)
  430.       if (pmbPrev->pmbNext == pmb) {
  431.          pmbPrev->pmbNext = pmb->pmbNext;
  432.          return;
  433.       }
  434. }
  435.  
  436. static void compact(void)
  437. {
  438.    PMEMBLOCK pmb;
  439.    int iFreed = 0;
  440.  
  441.    for (pmb=pmbFree->pmbNext; pmb; pmb=pmb->pmbNext) {
  442.       if (pmb == pmb->pmbNext) {
  443. #ifdef HEMP_DBG
  444.          ddprintf("~HEAP: heap loop, %p points to itself\n", (void __far *) pmb);
  445. #endif
  446.          int3();
  447.       }
  448.  
  449.       if (after(pmb)  == pmbFree) {
  450. #ifdef HEMP_DBG
  451. // ddprintf("~HEAP: compact found pointer %p (size=%u) before pmbFree %p\n", (void __far *) pmb, pmb->uSize, (void __far *) pmbFree);
  452. #endif
  453.          pmb->uSize += HDR_SIZE + pmbFree->uSize;
  454.          remove(pmbFree);
  455.          if (++iFreed == 2) goto exit;
  456.       } else if (after(pmbFree) == pmb) {
  457. #ifdef HEMP_DBG
  458. // ddprintf("~HEAP: compact found pointer %p (size=%u) after pmbFree %p\n", (void __far *) pmb, pmb->uSize, (void __far *) pmbFree);
  459. #endif
  460.          pmbFree->uSize += HDR_SIZE + pmb->uSize;
  461.          remove(pmb);
  462.          if (++iFreed == 2) goto exit;
  463.       }
  464.    }
  465.  
  466. exit:
  467.    nCompact += iFreed;
  468. }
  469.  
  470. void free(void __near *pvBlock)
  471. {
  472.    PMEMBLOCK pmb,pmbPrev,pmbBlock;
  473.    int fSentinel;
  474.  
  475.    ++nFreeCalls;
  476.    if (!pvBlock) return;     // support freeing of NULL
  477.  
  478.    pmbBlock=(PMEMBLOCK) ((char __near *) pvBlock - HDR_SIZE);
  479.  
  480.    //SignatureCheck( pmbBlock,(PSZ) "free() entry, Block to be freed" );
  481.    //SignatureCheck( pmbBlock,(PSZ)0);
  482.    SignatureCheck( pmbBlock,(PSZ)"FEBF");
  483.    //HeapCheck((PSZ) "free() entry" );
  484.    //HeapCheck((PSZ)0);
  485.    HeapCheck((PSZ)"FEXX");
  486.  
  487.    uMemFree += pmbBlock->uSize + HDR_SIZE;
  488.  
  489.    if (pmbBlock == pmbUsed) {       // are we freeing the first block?
  490.       pmbUsed = pmbUsed->pmbNext;   // the 2nd block is now the 1st
  491.       pmbBlock->pmbNext = pmbFree;  // this block is now free, so it points to 1st free block
  492.       pmbFree = pmbBlock;           // this is now the 1st free block
  493.       compact();
  494.       goto exit;
  495.    }
  496.  
  497.    pmbPrev=pmbUsed;
  498.    fSentinel = FALSE;
  499.    for (pmb=pmbUsed->pmbNext; pmb; pmbPrev=pmb, pmb=pmb->pmbNext)
  500.       if (pmb == pmbBlock) {
  501.          if (fSentinel) {
  502. #ifdef HEMP_DBG
  503.             ddprintf("~HEAP: free sentinel triggered, pmb=%p\n", (void __far *) pmb);
  504. #endif
  505.             int3();
  506.          }
  507.          pmbPrev->pmbNext = pmb->pmbNext;   // delete this block from the chain
  508.          pmbBlock->pmbNext = pmbFree;
  509.          pmbFree = pmbBlock;
  510.          compact();
  511.          fSentinel = TRUE;
  512.       }
  513.  
  514. exit: //--- Check things are still intact.
  515.    //HeapCheck((PSZ) "free() exit" );
  516.    //HeapCheck((PSZ)0);
  517.    HeapCheck((PSZ)"FXXX");
  518. }
  519.  
  520. unsigned _memfree(void)
  521. {
  522.    return uMemFree;
  523. }
  524.  
  525. void __near *realloc(void __near *pvBlock, unsigned usLength)
  526. {
  527.    void __near *pv;
  528.  
  529.    if (!pvBlock)                 // if ptr is null, alloc block
  530.       return malloc(usLength);
  531.  
  532.    if (!usLength) {              // if length is 0, free block
  533.       free(pvBlock);
  534.       return 0;
  535.    }
  536.  
  537.    pv=malloc(usLength);          // attempt to allocate the new block
  538.    if (!pv)                      // can't do it?
  539.       return 0;                  // just fail.  Version 2 will try harder
  540.  
  541.    MEMCPY(pv, pvBlock, min( _msize(pvBlock), usLength));
  542.    free(pvBlock);
  543.    return pv;
  544. }
  545.  
  546. #pragma code_seg ("_INITTEXT");
  547.  
  548. extern endHeap, endData;
  549.  
  550. // probably only want to use HEAP_SIZE for size since it's hard-coded a lot above
  551. // this uSize arg is probably for a future thing
  552.  
  553. unsigned HeapInit(unsigned uSize) {
  554.  
  555.  unsigned max_heap=((unsigned)&endHeap - (unsigned)&endData) & ~0xFFF; // align to K
  556.  
  557. // if (!uSize) uSize = DEFAULT_HEAP;
  558.  if (!uSize) uSize = HEAP_SIZE;
  559.  if (uSize > max_heap) uSize = max_heap;
  560.  
  561.  pmbFree=(PMEMBLOCK) acHeap;
  562.  pmbFree->uSize = uSize - HDR_SIZE;
  563.  pmbFree->ulSignature = SIGNATURE;
  564.  pmbFree->pmbNext = 0;
  565.  uMemFree = pmbFree->uSize;
  566.  
  567.  return pmbFree->uSize;
  568. }
  569.  
  570.  
  571.