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

  1. /***
  2. *malloc.c - Get a block of memory from the heap
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Defines the malloc() function.
  8. *
  9. *******************************************************************************/
  10.  
  11. #include <cruntime.h>
  12. #include <malloc.h>
  13. #include <internal.h>
  14. #include <mtdll.h>
  15. #include <dbgint.h>
  16.  
  17. #ifdef WINHEAP
  18. #include <windows.h>
  19. #include <winheap.h>
  20. #else  /* WINHEAP */
  21. #include <heap.h>
  22. #endif  /* WINHEAP */
  23.  
  24.  
  25. extern int _newmode;    /* malloc new() handler mode */
  26.  
  27.  
  28. /***
  29. *void *malloc(size_t size) - Get a block of memory from the heap
  30. *
  31. *Purpose:
  32. *       Allocate of block of memory of at least size bytes from the heap and
  33. *       return a pointer to it.
  34. *
  35. *       Calls the new appropriate new handler (if installed).
  36. *
  37. *Entry:
  38. *       size_t size - size of block requested
  39. *
  40. *Exit:
  41. *       Success:  Pointer to memory block
  42. *       Failure:  NULL (or some error value)
  43. *
  44. *Uses:
  45. *
  46. *Exceptions:
  47. *
  48. *******************************************************************************/
  49.  
  50. void * __cdecl _malloc_base (size_t size)
  51.  
  52. {
  53.         return _nh_malloc_base(size, _newmode);
  54. }
  55.  
  56.  
  57. /***
  58. *void *_nh_malloc_base(size_t size) - Get a block of memory from the heap
  59. *
  60. *Purpose:
  61. *       Allocate of block of memory of at least size bytes from the heap and
  62. *       return a pointer to it.
  63. *
  64. *       Calls the appropriate new handler (if installed).
  65. *
  66. *       There are two distinct new handler schemes supported. The 'new' ANSI
  67. *       C++ scheme overrides the 'old' scheme when it is activated. A value of
  68. *       _NOPTH for the 'new' handler indicates that it is inactivated and the
  69. *       'old' handler is then called.
  70. *
  71. *Entry:
  72. *       size_t size - size of block requested
  73. *
  74. *Exit:
  75. *       Success:  Pointer to memory block
  76. *       Failure:  NULL (or some error value)
  77. *
  78. *Uses:
  79. *
  80. *Exceptions:
  81. *
  82. *******************************************************************************/
  83.  
  84. void * __cdecl _nh_malloc_base (size_t size, int nhFlag)
  85. {
  86.         void * pvReturn;
  87.  
  88.         //  validate size
  89.         if (size > _HEAP_MAXREQ)
  90.             return NULL;
  91.  
  92. #ifndef WINHEAP
  93.         /* round requested size */
  94.         size = _ROUND2(size, _GRANULARITY);
  95. #endif  /* WINHEAP */
  96.  
  97.         for (;;) {
  98.  
  99.             //  allocate memory block
  100.             if (size <= _HEAP_MAXREQ)
  101.                 pvReturn = _heap_alloc_base(size);
  102.             else
  103.                 pvReturn = NULL;
  104.  
  105.             //  if successful allocation, return pointer to memory
  106.             //  if new handling turned off altogether, return NULL
  107.  
  108.             if (pvReturn || nhFlag == 0)
  109.                 return pvReturn;
  110.  
  111.             //  call installed new handler
  112.             if (!_callnewh(size))
  113.                 return NULL;
  114.  
  115.             //  new handler was successful -- try to allocate again
  116.         }
  117. }
  118.  
  119. /***
  120. *void *_heap_alloc_base(size_t size) - does actual allocation
  121. *
  122. *Purpose:
  123. *       Same as malloc() except the new handler is not called.
  124. *
  125. *Entry:
  126. *       See malloc
  127. *
  128. *Exit:
  129. *       See malloc
  130. *
  131. *Exceptions:
  132. *
  133. *******************************************************************************/
  134.  
  135. void * __cdecl _heap_alloc_base (size_t size)
  136.  
  137. {
  138. #ifdef WINHEAP
  139.         void * pvReturn;
  140. #else  /* WINHEAP */
  141.         _PBLKDESC pdesc;
  142.         _PBLKDESC pdesc2;
  143. #endif  /* WINHEAP */
  144.  
  145.  
  146. #ifdef WINHEAP
  147.  
  148.         if (size <= __sbh_threshold)
  149.         {
  150.             _mlock(_HEAP_LOCK);
  151.             pvReturn = __sbh_alloc_block(size);
  152.             _munlock(_HEAP_LOCK);
  153.             if (pvReturn)
  154.                 return pvReturn;
  155.         }
  156.  
  157.         if (size == 0)
  158.             size = 1;
  159.         size = (size + BYTES_PER_PARA - 1) & ~(BYTES_PER_PARA - 1);
  160.         return HeapAlloc(_crtheap, 0, size);
  161. }
  162.  
  163. #else  /* WINHEAP */
  164.  
  165.         /* try to find a big enough free block
  166.          */
  167.         if ( (pdesc = _heap_search(size)) == NULL )
  168.         {
  169.             if ( _heap_grow(size) != -1 )
  170.             {
  171.                 /* try finding a big enough free block again. the
  172.                  * success of the call to _heap_grow should guarantee
  173.                  * it, but...
  174.                  */
  175.                 if ( (pdesc = _heap_search(size)) == NULL )
  176.                 {
  177.                     /* something unexpected, and very bad, has
  178.                      * happened. abort!
  179.                      */
  180.                     _heap_abort();
  181.                 }
  182.             }
  183.             else
  184.                 return NULL;
  185.         }
  186.  
  187.         /* carve the block into two pieces (if necessary). the first piece
  188.          * shall be of the exact requested size, marked inuse and returned to
  189.          * the caller. the leftover piece is to be marked free.
  190.          */
  191.         if ( _BLKSIZE(pdesc) != size ) {
  192.             /* split up the block and free the leftover piece back to
  193.              * the heap
  194.              */
  195.             if ( (pdesc2 = _heap_split_block(pdesc, size)) != NULL )
  196.                 _SET_FREE(pdesc2);
  197.         }
  198.  
  199.         /* mark pdesc inuse
  200.          */
  201.         _SET_INUSE(pdesc);
  202.  
  203.         /* check proverdesc and reset, if necessary
  204.          */
  205.  
  206.         _heap_desc.proverdesc = pdesc->pnextdesc;
  207.  
  208.         return( (void *)((char *)_ADDRESS(pdesc) + _HDRSIZE) );
  209. }
  210.  
  211.  
  212. /***
  213. *_PBLKDESC _heap_split_block(pdesc, newsize) - split a heap allocation block
  214. *       into two allocation blocks
  215. *
  216. *Purpose:
  217. *       Split the allocation block described by pdesc into two blocks, the
  218. *       first one being of newsize bytes.
  219. *
  220. *       Notes: It is caller's responsibilty to set the status (i.e., free
  221. *       or inuse) of the two new blocks, and to check and reset proverdesc
  222. *       if necessary. See Exceptions (below) for additional requirements.
  223. *
  224. *Entry:
  225. *       _PBLKDESC pdesc - pointer to the allocation block descriptor
  226. *       size_t newsize  - size for the first of the two sub-blocks (i.e.,
  227. *                 (i.e., newsize == _BLKSIZE(pdesc), on exit)
  228. *
  229. *Exit:
  230. *       If successful, return a pointer to the descriptor for the leftover
  231. *       block.
  232. *       Otherwise, return NULL.
  233. *
  234. *Exceptions:
  235. *       It is assumed pdesc points to a valid allocation block descriptor and
  236. *       newsize is a valid heap block size as is (i.e., WITHOUT rounding). If
  237. *       either of these of assumption is violated, _heap_split_block() will
  238. *       likely corrupt the heap. Note also that _heap_split_block will simply
  239. *       return to the caller if newsize >= _BLKSIZE(pdesc), on entry.
  240. *
  241. *******************************************************************************/
  242.  
  243. _PBLKDESC __cdecl _heap_split_block (
  244.         REG1 _PBLKDESC pdesc,
  245.         size_t newsize
  246.         )
  247. {
  248.         REG2 _PBLKDESC pdesc2;
  249.  
  250.         _ASSERTE(("_heap_split_block: bad pdesc arg", _CHECK_PDESC(pdesc)));
  251.         _ASSERTE(("_heap_split_block: bad newsize arg", _ROUND2(newsize,_GRANULARITY) == newsize));
  252.  
  253.         /* carve the block into two pieces (if possible). the first piece
  254.          * is to be exactly newsize bytes.
  255.          */
  256.         if ( (_BLKSIZE(pdesc) > newsize) && ((pdesc2 = __getempty())
  257.                != NULL) )
  258.         {
  259.             /* set it up to manage the second piece and link it in to
  260.              * the list
  261.              */
  262.             pdesc2->pblock = (void *)((char *)_ADDRESS(pdesc) + newsize +
  263.                      _HDRSIZE);
  264.             *(void **)(pdesc2->pblock) = pdesc2;
  265.             pdesc2->pnextdesc = pdesc->pnextdesc;
  266.             pdesc->pnextdesc = pdesc2;
  267.  
  268.             return pdesc2;
  269.         }
  270.         return NULL;
  271. }
  272.  
  273. #endif  /* WINHEAP */
  274.  
  275.