Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

436 lines
10 KiB

  1. /***
  2. *heapgrow.c - Grow the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Get memory from OS and add to the heap.
  8. *
  9. *Revision History:
  10. * 06-06-89 JCR Module created.
  11. * 07-19-89 JCR Added region support
  12. * 11-07-89 JCR Region table is no longer "packed"
  13. * 11-08-89 JCR Use new _ROUND/_ROUND2 macros
  14. * 11-10-89 JCR Don't abort on ERROR_NOT_ENOUGH_MEMORY
  15. * 11-13-89 GJF Fixed copyright
  16. * 12-18-89 GJF Removed DEBUG286 stuff, a little tuning, cleaned up
  17. * the formatting a bit, changed header file name to
  18. * heap.h, also added _cdecl to functions (that didn't
  19. * already have explicit calling type)
  20. * 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  21. * <cruntime.h> and removed #include <register.h>.
  22. * 03-29-90 GJF Made _heap_new_region() _CALLTYPE4.
  23. * 07-24-90 SBM Compiles cleanly with -W3 (tentatively removed
  24. * unreferenced labels), removed '32' from API names
  25. * 09-28-90 GJF New-style function declarators.
  26. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  27. * 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
  28. * 02-01-91 SRW Changed for new VirtualAlloc interface (_WIN32_)
  29. * 04-09-91 PNT Added _MAC_ conditional
  30. * 04-26-91 SRW Removed level 3 warnings
  31. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  32. * 04-26-93 SKS Change _HEAP_MAXREGIONSIZE to _heap_maxregsize
  33. * 09-06-94 CFW Remove Cruiser support.
  34. * 02-14-95 GJF Appended Mac version of source file.
  35. * 04-30-95 GJF Made conditional on WINHEAP.
  36. * 05-17-99 PML Remove all Macintosh support.
  37. *
  38. *******************************************************************************/
  39. #ifndef WINHEAP
  40. #include <cruntime.h>
  41. #include <oscalls.h>
  42. #include <heap.h>
  43. #include <malloc.h>
  44. #include <stdlib.h>
  45. static int __cdecl _heap_new_region(unsigned, size_t);
  46. /***
  47. *_heap_grow() - Grow the heap
  48. *
  49. *Purpose:
  50. * Get memory from the OS and add it to the heap.
  51. *
  52. *Entry:
  53. * size_t _size = user's block request
  54. *
  55. *Exit:
  56. * 0 = success, new mem is in the heap
  57. * -1 = failure
  58. *
  59. *Exceptions:
  60. *
  61. *******************************************************************************/
  62. int __cdecl _heap_grow (
  63. REG1 size_t size
  64. )
  65. {
  66. REG2 int index;
  67. int free_entry = -1;
  68. /*
  69. * Bump size to include header and round to nearest page boundary.
  70. */
  71. size += _HDRSIZE;
  72. size = _ROUND2(size,_PAGESIZE_);
  73. /*
  74. * Loop through the region table looking for an existing region
  75. * we can grow. Remember the index of the first null region entry.
  76. *
  77. * size = size of grow request
  78. */
  79. for (index = 0; index < _HEAP_REGIONMAX; index++) {
  80. if ( (_heap_regions[index]._totalsize -
  81. _heap_regions[index]._currsize) >= size )
  82. /*
  83. * Grow this region to satisfy the request.
  84. */
  85. return( _heap_grow_region(index, size) );
  86. if ( (free_entry == -1) &&
  87. (_heap_regions[index]._regbase == NULL) )
  88. /*
  89. * Remember 1st free table entry for later
  90. */
  91. free_entry = index;
  92. }
  93. /*
  94. * Could not find any existing regions to grow. Try to
  95. * get a new region.
  96. *
  97. * size = size of grow request
  98. * free_entry = index of first free entry in table
  99. */
  100. if ( free_entry >= 0 )
  101. /*
  102. * Get a new region to satisfy the request.
  103. */
  104. return( _heap_new_region(free_entry, size) );
  105. else
  106. /*
  107. * No free table entries: return an error.
  108. */
  109. return(-1);
  110. }
  111. /***
  112. *_heap_new_region() - Get a new heap region
  113. *
  114. *Purpose:
  115. * Get a new heap region and put it in the region table.
  116. * Also, grow it large enough to support the caller's
  117. * request.
  118. *
  119. * NOTES:
  120. * (1) Caller has verified that there is room in the _heap_region
  121. * table for another region.
  122. * (2) The caller must have rounded the size to a page boundary.
  123. *
  124. *Entry:
  125. * int index = index in table where new region data should go
  126. * size_t size = size of request (this has been rounded to a
  127. * page-sized boundary)
  128. *
  129. *Exit:
  130. * 0 = success
  131. * -1 = failure
  132. *
  133. *Exceptions:
  134. *
  135. *******************************************************************************/
  136. static int __cdecl _heap_new_region (
  137. REG1 unsigned index,
  138. size_t size
  139. )
  140. {
  141. void * region;
  142. REG2 unsigned int regsize;
  143. #ifdef DEBUG
  144. int i;
  145. /*
  146. * Make sure the size has been rounded to a page boundary
  147. */
  148. if (size & (_PAGESIZE_-1))
  149. _heap_abort();
  150. /*
  151. * Make sure there's a free slot in the table
  152. */
  153. for (i=0; i < _HEAP_REGIONMAX; i++) {
  154. if (_heap_regions[i]._regbase == NULL)
  155. break;
  156. }
  157. if (i >= _HEAP_REGIONMAX)
  158. _heap_abort();
  159. #endif
  160. /*
  161. * Round the heap region size to a page boundary (in case
  162. * the user played with it).
  163. */
  164. regsize = _ROUND2(_heap_regionsize, _PAGESIZE_);
  165. /*
  166. * To acommodate large users, request twice
  167. * as big a region next time around.
  168. */
  169. if ( _heap_regionsize < _heap_maxregsize )
  170. _heap_regionsize *= 2 ;
  171. /*
  172. * See if region is big enough for request
  173. */
  174. if (regsize < size)
  175. regsize = size;
  176. /*
  177. * Go get the new region
  178. */
  179. if (!(region = VirtualAlloc(NULL, regsize, MEM_RESERVE,
  180. PAGE_READWRITE)))
  181. goto error;
  182. /*
  183. * Put the new region in the table.
  184. */
  185. _heap_regions[index]._regbase = region;
  186. _heap_regions[index]._totalsize = regsize;
  187. _heap_regions[index]._currsize = 0;
  188. /*
  189. * Grow the region to satisfy the size request.
  190. */
  191. if (_heap_grow_region(index, size) != 0) {
  192. /*
  193. * Ouch. Allocated a region but couldn't commit
  194. * any pages in it. Free region and return error.
  195. */
  196. _heap_free_region(index);
  197. goto error;
  198. }
  199. /*
  200. * Good return
  201. */
  202. /* done: unreferenced label to be removed */
  203. return(0);
  204. /*
  205. * Error return
  206. */
  207. error:
  208. return(-1);
  209. }
  210. /***
  211. *_heap_grow_region() - Grow a heap region
  212. *
  213. *Purpose:
  214. * Grow a region and add the new memory to the heap.
  215. *
  216. * NOTES:
  217. * (1) The caller must have rounded the size to a page boundary.
  218. *
  219. *Entry:
  220. * unsigned index = index of region in the _heap_regions[] table
  221. * size_t size = size of request (this has been rounded to a
  222. * page-sized boundary)
  223. *
  224. *Exit:
  225. * 0 = success
  226. * -1 = failure
  227. *
  228. *Exceptions:
  229. *
  230. *******************************************************************************/
  231. int __cdecl _heap_grow_region (
  232. REG1 unsigned index,
  233. size_t size
  234. )
  235. {
  236. size_t left;
  237. REG2 size_t growsize;
  238. void * base;
  239. unsigned dosretval;
  240. /*
  241. * Init some variables
  242. * left = space left in region
  243. * base = base of next section of region to validate
  244. */
  245. left = _heap_regions[index]._totalsize -
  246. _heap_regions[index]._currsize;
  247. base = (char *) _heap_regions[index]._regbase +
  248. _heap_regions[index]._currsize;
  249. /*
  250. * Make sure we can satisfy request
  251. */
  252. if (left < size)
  253. goto error;
  254. /*
  255. * Round size up to next _heap_growsize boundary.
  256. * (Must round _heap_growsize itself to page boundary, in
  257. * case user set it himself).
  258. */
  259. growsize = _ROUND2(_heap_growsize, _PAGESIZE_);
  260. growsize = _ROUND(size, growsize);
  261. if (left < growsize)
  262. growsize = left;
  263. /*
  264. * Validate the new portion of the region
  265. */
  266. if (!VirtualAlloc(base, growsize, MEM_COMMIT, PAGE_READWRITE))
  267. dosretval = GetLastError();
  268. else
  269. dosretval = 0;
  270. if (dosretval)
  271. /*
  272. * Error committing pages. If out of memory, return
  273. * error, else abort.
  274. */
  275. if (dosretval == ERROR_NOT_ENOUGH_MEMORY)
  276. goto error;
  277. else
  278. _heap_abort();
  279. /*
  280. * Update the region data base
  281. */
  282. _heap_regions[index]._currsize += growsize;
  283. #ifdef DEBUG
  284. /*
  285. * The current size should never be greater than the total size
  286. */
  287. if (_heap_regions[index]._currsize > _heap_regions[index]._totalsize)
  288. _heap_abort();
  289. #endif
  290. /*
  291. * Add the memory to the heap
  292. */
  293. if (_heap_addblock(base, growsize) != 0)
  294. _heap_abort();
  295. /*
  296. * Good return
  297. */
  298. /* done: unreferenced label to be removed */
  299. return(0);
  300. /*
  301. * Error return
  302. */
  303. error:
  304. return(-1);
  305. }
  306. /***
  307. *_heap_free_region() - Free up a region
  308. *
  309. *Purpose:
  310. * Return a heap region to the OS and zero out
  311. * corresponding region data entry.
  312. *
  313. *Entry:
  314. * int index = index of region to be freed
  315. *
  316. *Exit:
  317. * void
  318. *
  319. *Exceptions:
  320. *
  321. *******************************************************************************/
  322. void __cdecl _heap_free_region (
  323. REG1 int index
  324. )
  325. {
  326. /*
  327. * Give the memory back to the OS
  328. */
  329. if (!VirtualFree(_heap_regions[index]._regbase, 0, MEM_RELEASE))
  330. _heap_abort();
  331. /*
  332. * Zero out the heap region entry
  333. */
  334. _heap_regions[index]._regbase = NULL;
  335. _heap_regions[index]._currsize =
  336. _heap_regions[index]._totalsize = 0;
  337. }
  338. #endif /* WINHEAP */