home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / heapgrow.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  20KB  |  790 lines

  1. /***
  2. *heapgrow.c - Grow the heap
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Get memory from OS and add to the heap.
  8. *
  9. *******************************************************************************/
  10.  
  11. #ifndef WINHEAP
  12.  
  13. #ifdef _WIN32
  14.  
  15.  
  16. #include <cruntime.h>
  17. #include <oscalls.h>
  18. #include <heap.h>
  19. #include <malloc.h>
  20. #include <stdlib.h>
  21.  
  22. static int __cdecl _heap_new_region(unsigned, size_t);
  23.  
  24.  
  25. /***
  26. *_heap_grow() - Grow the heap
  27. *
  28. *Purpose:
  29. *       Get memory from the OS and add it to the heap.
  30. *
  31. *Entry:
  32. *       size_t _size = user's block request
  33. *
  34. *Exit:
  35. *        0 = success, new mem is in the heap
  36. *       -1 = failure
  37. *
  38. *Exceptions:
  39. *
  40. *******************************************************************************/
  41.  
  42. int __cdecl _heap_grow (
  43.         REG1 size_t size
  44.         )
  45. {
  46.         REG2 int index;
  47.         int free_entry = -1;
  48.  
  49.         /*
  50.          * Bump size to include header and round to nearest page boundary.
  51.          */
  52.  
  53.         size += _HDRSIZE;
  54.         size = _ROUND2(size,_PAGESIZE_);
  55.  
  56.         /*
  57.          * Loop through the region table looking for an existing region
  58.          * we can grow.  Remember the index of the first null region entry.
  59.          *
  60.          * size = size of grow request
  61.          */
  62.  
  63.         for (index = 0; index < _HEAP_REGIONMAX; index++) {
  64.  
  65.                 if ( (_heap_regions[index]._totalsize -
  66.                     _heap_regions[index]._currsize) >= size )
  67.  
  68.                         /*
  69.                          * Grow this region to satisfy the request.
  70.                          */
  71.  
  72.                         return( _heap_grow_region(index, size) );
  73.  
  74.  
  75.                 if ( (free_entry == -1) &&
  76.                     (_heap_regions[index]._regbase == NULL) )
  77.  
  78.                         /*
  79.                          * Remember 1st free table entry for later
  80.                          */
  81.  
  82.                         free_entry = index;
  83.  
  84.         }
  85.  
  86.         /*
  87.          * Could not find any existing regions to grow.  Try to
  88.          * get a new region.
  89.          *
  90.          * size = size of grow request
  91.          * free_entry = index of first free entry in table
  92.          */
  93.  
  94.         if ( free_entry >= 0 )
  95.  
  96.                 /*
  97.                  * Get a new region to satisfy the request.
  98.                  */
  99.  
  100.                 return( _heap_new_region(free_entry, size) );
  101.  
  102.         else
  103.                 /*
  104.                  * No free table entries: return an error.
  105.                  */
  106.  
  107.                 return(-1);
  108.  
  109. }
  110.  
  111.  
  112. /***
  113. *_heap_new_region() - Get a new heap region
  114. *
  115. *Purpose:
  116. *       Get a new heap region and put it in the region table.
  117. *       Also, grow it large enough to support the caller's
  118. *       request.
  119. *
  120. *       NOTES:
  121. *       (1) Caller has verified that there is room in the _heap_region
  122. *       table for another region.
  123. *       (2) The caller must have rounded the size to a page boundary.
  124. *
  125. *Entry:
  126. *       int index = index in table where new region data should go
  127. *       size_t size = size of request (this has been rounded to a
  128. *                       page-sized boundary)
  129. *
  130. *Exit:
  131. *        0 = success
  132. *       -1 = failure
  133. *
  134. *Exceptions:
  135. *
  136. *******************************************************************************/
  137.  
  138. static int __cdecl _heap_new_region (
  139.         REG1 unsigned index,
  140.         size_t size
  141.         )
  142. {
  143.         void * region;
  144.         REG2 unsigned int regsize;
  145.  
  146.  
  147.         /*
  148.          * Round the heap region size to a page boundary (in case
  149.          * the user played with it).
  150.          */
  151.  
  152.         regsize = _ROUND2(_heap_regionsize, _PAGESIZE_);
  153.  
  154.         /*
  155.          * To acommodate large users, request twice
  156.          * as big a region next time around.
  157.          */
  158.  
  159.         if ( _heap_regionsize < _heap_maxregsize )
  160.                 _heap_regionsize *= 2 ;
  161.  
  162.         /*
  163.          * See if region is big enough for request
  164.          */
  165.  
  166.         if (regsize < size)
  167.                 regsize = size;
  168.  
  169.         /*
  170.          * Go get the new region
  171.          */
  172.  
  173.         if (!(region = VirtualAlloc(NULL, regsize, MEM_RESERVE,
  174.         PAGE_READWRITE)))
  175.                 goto error;
  176.  
  177.         /*
  178.          * Put the new region in the table.
  179.          */
  180.  
  181.          _heap_regions[index]._regbase = region;
  182.          _heap_regions[index]._totalsize = regsize;
  183.          _heap_regions[index]._currsize = 0;
  184.  
  185.  
  186.         /*
  187.          * Grow the region to satisfy the size request.
  188.          */
  189.  
  190.         if (_heap_grow_region(index, size) != 0) {
  191.  
  192.                 /*
  193.                  * Ouch.  Allocated a region but couldn't commit
  194.                  * any pages in it.  Free region and return error.
  195.                  */
  196.  
  197.                 _heap_free_region(index);
  198.                 goto error;
  199.         }
  200.  
  201.  
  202.         /*
  203.          * Good return
  204.          */
  205.  
  206.         /* done:   unreferenced label to be removed */
  207.                 return(0);
  208.  
  209.         /*
  210.          * Error return
  211.          */
  212.  
  213.         error:
  214.                 return(-1);
  215.  
  216. }
  217.  
  218.  
  219. /***
  220. *_heap_grow_region() - Grow a heap region
  221. *
  222. *Purpose:
  223. *       Grow a region and add the new memory to the heap.
  224. *
  225. *       NOTES:
  226. *       (1) The caller must have rounded the size to a page boundary.
  227. *
  228. *Entry:
  229. *       unsigned index = index of region in the _heap_regions[] table
  230. *       size_t size = size of request (this has been rounded to a
  231. *                       page-sized boundary)
  232. *
  233. *Exit:
  234. *        0 = success
  235. *       -1 = failure
  236. *
  237. *Exceptions:
  238. *
  239. *******************************************************************************/
  240.  
  241. int __cdecl _heap_grow_region (
  242.         REG1 unsigned index,
  243.         size_t size
  244.         )
  245. {
  246.         size_t left;
  247.         REG2 size_t growsize;
  248.         void * base;
  249.         unsigned dosretval;
  250.  
  251.  
  252.         /*
  253.          * Init some variables
  254.          * left = space left in region
  255.          * base = base of next section of region to validate
  256.          */
  257.  
  258.         left = _heap_regions[index]._totalsize -
  259.                 _heap_regions[index]._currsize;
  260.  
  261.         base = (char *) _heap_regions[index]._regbase +
  262.                 _heap_regions[index]._currsize;
  263.  
  264.         /*
  265.          * Make sure we can satisfy request
  266.          */
  267.  
  268.         if (left < size)
  269.                 goto error;
  270.  
  271.         /*
  272.          * Round size up to next _heap_growsize boundary.
  273.          * (Must round _heap_growsize itself to page boundary, in
  274.          * case user set it himself).
  275.          */
  276.  
  277.         growsize = _ROUND2(_heap_growsize, _PAGESIZE_);
  278.         growsize = _ROUND(size, growsize);
  279.  
  280.         if (left < growsize)
  281.                 growsize = left;
  282.  
  283.         /*
  284.          * Validate the new portion of the region
  285.          */
  286.  
  287.         if (!VirtualAlloc(base, growsize, MEM_COMMIT, PAGE_READWRITE))
  288.                 dosretval = GetLastError();
  289.         else
  290.                 dosretval = 0;
  291.  
  292.         if (dosretval)
  293.                 /*
  294.                  * Error committing pages.  If out of memory, return
  295.                  * error, else abort.
  296.                  */
  297.  
  298.                 if (dosretval == ERROR_NOT_ENOUGH_MEMORY)
  299.                         goto error;
  300.                 else
  301.                         _heap_abort();
  302.  
  303.  
  304.         /*
  305.          * Update the region data base
  306.          */
  307.  
  308.         _heap_regions[index]._currsize += growsize;
  309.  
  310.  
  311.  
  312.  
  313.         /*
  314.          * Add the memory to the heap
  315.          */
  316.  
  317.         if (_heap_addblock(base, growsize) != 0)
  318.                 _heap_abort();
  319.  
  320.  
  321.         /*
  322.          * Good return
  323.          */
  324.  
  325.         /* done:   unreferenced label to be removed */
  326.                 return(0);
  327.  
  328.         /*
  329.          * Error return
  330.          */
  331.  
  332.         error:
  333.                 return(-1);
  334.  
  335. }
  336.  
  337.  
  338. /***
  339. *_heap_free_region() - Free up a region
  340. *
  341. *Purpose:
  342. *       Return a heap region to the OS and zero out
  343. *       corresponding region data entry.
  344. *
  345. *Entry:
  346. *       int index = index of region to be freed
  347. *
  348. *Exit:
  349. *       void
  350. *
  351. *Exceptions:
  352. *
  353. *******************************************************************************/
  354.  
  355. void __cdecl _heap_free_region (
  356.         REG1 int index
  357.         )
  358. {
  359.  
  360.         /*
  361.          * Give the memory back to the OS
  362.          */
  363.  
  364.         if (!VirtualFree(_heap_regions[index]._regbase, 0, MEM_RELEASE))
  365.                 _heap_abort();
  366.  
  367.         /*
  368.          * Zero out the heap region entry
  369.          */
  370.  
  371.         _heap_regions[index]._regbase = NULL;
  372.         _heap_regions[index]._currsize =
  373.         _heap_regions[index]._totalsize = 0;
  374.  
  375. }
  376.  
  377.  
  378. #else  /* _WIN32 */
  379.  
  380. #if defined (_M_MPPC) || defined (_M_M68K)
  381.  
  382.  
  383. #include <cruntime.h>
  384. #include <heap.h>
  385. #include <malloc.h>
  386. #include <stdlib.h>
  387. #include <string.h>
  388. #include <macos\memory.h>               // Mac OS interface header
  389. #include <macos\errors.h>
  390. #include <macos\types.h>
  391. #include <macos\traps.h>
  392.  
  393. static int __cdecl _heap_new_region(unsigned, size_t);
  394. extern Handle hHeapRegions;
  395. extern int _heap_region_table_cur;
  396.  
  397. static unsigned short *pMemErr = (unsigned short *)0x220;
  398. static int index_start = 0;
  399.  
  400. /***
  401. *_heap_grow() - Grow the heap
  402. *
  403. *Purpose:
  404. *       Get memory from the OS and add it to the heap.
  405. *
  406. *Entry:
  407. *       size_t _size = user's block request
  408. *
  409. *Exit:
  410. *        0 = success, new mem is in the heap
  411. *       -1 = failure
  412. *
  413. *Exceptions:
  414. *
  415. *******************************************************************************/
  416.  
  417. int __cdecl _heap_grow (
  418.         REG1 size_t size
  419.         )
  420. {
  421.         REG2 int index;
  422.         struct _heap_region_ *pHeapRegions;
  423.         int free_entry = -1;
  424.         size_t sizeTmp;
  425.         Handle hTemp;
  426.  
  427.         /*
  428.          * Bump size to include header and round to nearest page boundary.
  429.          */
  430.  
  431.         size += _HDRSIZE;
  432.         size = _ROUND2(size, _GRANULARITY);
  433.  
  434.         /*
  435.          * Loop through the region table looking for an existing region
  436.          * we can grow.  Remember the index of the first null region entry.
  437.          *
  438.          * size = size of grow request
  439.          */
  440.  
  441.         for ( index=index_start ; index < _heap_region_table_cur; index++ ) {
  442.  
  443.                 pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
  444.                         /*
  445.                          * Grow this region to satisfy the request.
  446.                          */
  447.                 if ( (pHeapRegions+index)->_regbase != NULL)
  448.                         {
  449.                         if (_heap_grow_region(index, size) != -1)
  450.                                 {
  451.                                 index_start = index;
  452.                                 return 0;
  453.                                 }
  454.                         }
  455.  
  456.                 pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
  457.                 if ( (free_entry == -1) &&
  458.                     ((pHeapRegions+index)->_regbase == NULL) )
  459.  
  460.                         /*
  461.                          * Remember 1st free table entry for later
  462.                          */
  463.                         {
  464.                         free_entry = index;
  465.                         break;
  466.                         }
  467.  
  468.         }
  469.  
  470.         /*
  471.          * Could not find any existing regions to grow.  Try to
  472.          * get a new region.
  473.          *
  474.          * size = size of grow request
  475.          * free_entry = index of first free entry in table
  476.          */
  477.  
  478.         if ( free_entry == -1)
  479.                 /*
  480.                  * No free table entries: grow heap region table.
  481.                  */
  482.                 {
  483.                 sizeTmp = sizeof(struct _heap_region_)*(_heap_region_table_cur+_HEAP_REGIONMAX);
  484.                 if (hHeapRegions)
  485.                         {
  486.                         SetHandleSize(hHeapRegions, sizeTmp);
  487.                         }
  488.                 if (hHeapRegions== NULL || *pMemErr != 0)
  489.                         {
  490.                         /*
  491.                          * grow failed
  492.                          */
  493.                         hTemp = NewHandle(sizeTmp);
  494.                         if (hTemp == NULL)
  495.                                 {
  496.                                 return (-1);
  497.                                 }
  498.                         HLock(hTemp);
  499.                         if (hHeapRegions != NULL)
  500.                                 {
  501.                                 BlockMove(*hHeapRegions, *hTemp, sizeof(struct _heap_region_)*_heap_region_table_cur);
  502.                                 DisposeHandle(hHeapRegions);
  503.                                 }
  504.                         hHeapRegions = hTemp;
  505.                         }
  506.                 /*
  507.                  * set rest of the table to zero
  508.                  */
  509.                 memset(*hHeapRegions + sizeof(struct _heap_region_)*_heap_region_table_cur, 0, sizeof(struct _heap_region_)*_HEAP_REGIONMAX);
  510.                 free_entry = _heap_region_table_cur;
  511.                 _heap_region_table_cur += _HEAP_REGIONMAX;
  512.                 }
  513.         /*
  514.          * Get a new region to satisfy the request.
  515.          */
  516.  
  517.         return( _heap_new_region(free_entry, size) );
  518. }
  519.  
  520.  
  521. /***
  522. *_heap_new_region() - Get a new heap region
  523. *
  524. *Purpose:
  525. *       Get a new heap region and put it in the region table.
  526. *       Also, grow it large enough to support the caller's
  527. *       request.
  528. *
  529. *       NOTES:
  530. *       (1) Caller has verified that there is room in the _heap_region
  531. *       table for another region.
  532. *       (2) The caller must have rounded the size to a page boundary.
  533. *
  534. *Entry:
  535. *       int index = index in table where new region data should go
  536. *       size_t size = size of request (this has been rounded to a
  537. *                       page-sized boundary)
  538. *
  539. *Exit:
  540. *        0 = success
  541. *       -1 = failure
  542. *
  543. *Exceptions:
  544. *
  545. *******************************************************************************/
  546.  
  547. static int __cdecl _heap_new_region (
  548.         REG1 unsigned index,
  549.         size_t size
  550.         )
  551. {
  552.         void * region;
  553.         REG2 unsigned int regsize;
  554.         struct _heap_region_ *pHeapRegions;
  555.  
  556.  
  557.         /*
  558.          * Round the heap region size to a page boundary (in case
  559.          * the user played with it).
  560.          */
  561.  
  562.         regsize = _ROUND2(_heap_regionsize, _PAGESIZE_);
  563.  
  564.         /*
  565.          * See if region is big enough for request
  566.          */
  567.  
  568.         if (regsize < size)
  569.                 regsize = size;
  570.  
  571.         /*
  572.          * Go get the new region
  573.          */
  574.  
  575. #ifdef _M_MPPC
  576.         if ((region = NewPtr(regsize + 8)) == NULL)
  577. #else  /* _M_MPPC */
  578.         if ((region = NewPtr(regsize + 4)) == NULL)
  579. #endif  /* _M_MPPC */
  580.                 {
  581.                 goto error;
  582.                 }
  583.  
  584.         /*
  585.          * Put the new region in the table.
  586.          */
  587.  
  588.         pHeapRegions = (struct _heap_region_ *)*hHeapRegions;
  589.         if (((unsigned long)region & 0x3) != 0)
  590.                 {
  591.                 /* we are not allocating at 4 bytes bound */
  592.                 (pHeapRegions + index)->_regbase = (void *)_ROUND2((size_t)region, _GRANULARITY);
  593.                 }
  594.         else
  595.                 {
  596.                 (pHeapRegions + index)->_regbase = region;
  597.                 }
  598.  
  599.         (pHeapRegions + index)->_regbaseCopy = region;
  600.         (pHeapRegions + index)->_totalsize = regsize;
  601.         (pHeapRegions + index)->_currsize = 0;
  602.  
  603.  
  604.         /*
  605.          * Grow the region to satisfy the size request.
  606.          */
  607.  
  608.         if (_heap_grow_region(index, size) != 0) {
  609.  
  610.                 /*
  611.                  * Ouch.  Allocated a region but couldn't commit
  612.                  * any pages in it.  Free region and return error.
  613.                  */
  614.  
  615.                 _heap_free_region(index);
  616.                 goto error;
  617.         }
  618.  
  619.  
  620.         /*
  621.          * Good return
  622.          */
  623.  
  624.         /* done:   unreferenced label to be removed */
  625.                 return(0);
  626.  
  627.         /*
  628.          * Error return
  629.          */
  630.  
  631.         error:
  632.                 return(-1);
  633.  
  634. }
  635.  
  636.  
  637. /***
  638. *_heap_grow_region() - Grow a heap region
  639. *
  640. *Purpose:
  641. *       Grow a region and add the new memory to the heap.
  642. *
  643. *       NOTES:
  644. *       (1) The caller must have rounded the size to a page boundary.
  645. *
  646. *Entry:
  647. *       unsigned index = index of region in the _heap_regions[] table
  648. *       size_t size = size of request (this has been rounded to a
  649. *                       page-sized boundary)
  650. *
  651. *Exit:
  652. *        0 = success
  653. *       -1 = failure
  654. *
  655. *Exceptions:
  656. *
  657. *******************************************************************************/
  658.  
  659. int __cdecl _heap_grow_region (
  660.         REG1 unsigned index,
  661.         size_t size
  662.         )
  663. {
  664.         size_t left;
  665.         REG2 size_t growsize;
  666.         void * base;
  667.         struct _heap_region_ *pHeapRegions;
  668.         struct _heap_region_ *pHRTmp;
  669.  
  670.  
  671.         /*
  672.          * Init some variables
  673.          * left = space left in region
  674.          * base = base of next section of region to validate
  675.          */
  676.  
  677.         pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
  678.         pHRTmp = pHeapRegions + index;
  679.         left = pHRTmp->_totalsize - pHRTmp->_currsize;
  680.  
  681.         base = (char *) (pHRTmp->_regbase) + pHRTmp->_currsize;
  682.  
  683.         /*
  684.          * Make sure we can satisfy request
  685.          */
  686.         growsize = _ROUND2(size, _GRANULARITY);
  687.  
  688.         if (left < growsize)
  689.                 {
  690.                 size_t sizeTmp;
  691.  
  692.                 sizeTmp = growsize-left+1+ pHRTmp->_totalsize;
  693.                 sizeTmp = _ROUND2(sizeTmp, _GRANULARITY);
  694.                 SetPtrSize(pHRTmp->_regbase, sizeTmp);
  695.                 pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
  696.                 pHRTmp = pHeapRegions + index;
  697.                 if (*pMemErr != 0)
  698.                         {
  699.                         goto error;
  700.                         }
  701.                 pHRTmp->_totalsize = sizeTmp;
  702.                 left = sizeTmp - pHRTmp->_currsize;
  703.                 base = (char *) (pHRTmp->_regbase) + pHRTmp->_currsize;
  704.                 }
  705.  
  706.         /*
  707.          * Update the region data base
  708.          */
  709.  
  710.         pHRTmp->_currsize += growsize;
  711.  
  712.  
  713.  
  714.  
  715.         /*
  716.          * Add the memory to the heap
  717.          */
  718.  
  719.         if (_heap_addblock(base, growsize) != 0)
  720.                 _heap_abort();
  721.  
  722.  
  723.         /*
  724.          * Good return
  725.          */
  726.  
  727.         /* done:   unreferenced label to be removed */
  728.                 return(0);
  729.  
  730.         /*
  731.          * Error return
  732.          */
  733.  
  734.         error:
  735.                 return(-1);
  736.  
  737. }
  738.  
  739.  
  740. /***
  741. *_heap_free_region() - Free up a region
  742. *
  743. *Purpose:
  744. *       Return a heap region to the OS and zero out
  745. *       corresponding region data entry.
  746. *
  747. *Entry:
  748. *       int index = index of region to be freed
  749. *
  750. *Exit:
  751. *       void
  752. *
  753. *Exceptions:
  754. *
  755. *******************************************************************************/
  756.  
  757. void __cdecl _heap_free_region (
  758.         REG1 int index
  759.         )
  760. {
  761.         struct _heap_region_ *pHeapRegions;
  762.  
  763.         /*
  764.          * Give the memory back to the OS
  765.          */
  766.  
  767.         pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
  768.         if ((pHeapRegions + index)->_regbase)
  769.                 {
  770.                 DisposePtr((pHeapRegions + index)->_regbaseCopy);
  771.                 }
  772.  
  773.         /*
  774.          * Zero out the heap region entry
  775.          */
  776.  
  777.         pHeapRegions = (struct _heap_region_ *)(*hHeapRegions);
  778.         (pHeapRegions + index)->_regbase = NULL;
  779.         (pHeapRegions + index)->_currsize = 0;
  780.         (pHeapRegions + index)->_totalsize = 0;
  781.  
  782. }
  783.  
  784.  
  785. #endif  /* defined (_M_MPPC) || defined (_M_M68K) */
  786.  
  787. #endif  /* _WIN32 */
  788.  
  789. #endif  /* WINHEAP */
  790.