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.

477 lines
10 KiB

  1. /***
  2. *heapadd.c - Add a block of memory to the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Add a block of memory to the heap.
  8. *
  9. *Revision History:
  10. * 07-07-89 JCR Module created.
  11. * 07-20-89 JCR Re-use dummy descriptor on exact fit (dummy collection)
  12. * 11-09-89 JCR Corrected plastdesc updating code
  13. * 11-13-89 GJF Added MTHREAD support, also fixed copyright
  14. * 11-15-89 JCR Minor improvement (got rid of a local variable)
  15. * 11-16-89 JCR Bug fix - squirrly case in _HEAPFIND_EXACT
  16. * 12-04-89 GJF A little tuning and cleanup. Also, changed header file
  17. * name to heap.h.
  18. * 12-18-89 GJF Removed DEBUG286 stuff. Also, added explicit _cdecl to
  19. * function definitions.
  20. * 12-19-89 GJF Removed references and uses of plastdesc (revising
  21. * code as necessary)
  22. * 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  23. * <cruntime.h> and removed #include <register.h>.
  24. * 03-29-90 GJF Made _before() _CALLTYPE4.
  25. * 07-24-90 SBM Compiles cleanly with -W3 (tentatively removed
  26. * unreferenced label)
  27. * 09-27-90 GJF New-style function declarators.
  28. * 03-05-91 GJF Changed strategy for rover - old version available
  29. * by #define-ing _OLDROVER_.
  30. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  31. * 12-10-93 GJF Test alignment of user's pointer and block size
  32. * against _GRANULARITY.
  33. * 01-03-94 SKS Fix bug where sentinel gets out of sync with dummy
  34. * blocks and large allocations. _heapmin was likely
  35. * to cause the situation that showed the bug.
  36. * 03-03-94 GJF Revised to provide for graceful failure in the event
  37. * there aren't enough empty descriptors.
  38. * 02-08-95 GJF Removed obsolete _OLDROVER_ support.
  39. * 04-29-95 GJF Spliced on winheap version.
  40. *
  41. *******************************************************************************/
  42. #ifdef WINHEAP
  43. #include <cruntime.h>
  44. #include <errno.h>
  45. #include <malloc.h>
  46. #include <winheap.h>
  47. int __cdecl _heapadd (
  48. void * block,
  49. size_t size
  50. )
  51. {
  52. errno = ENOSYS;
  53. return(-1);
  54. }
  55. #else /* ndef WINHEAP */
  56. #include <cruntime.h>
  57. #include <heap.h>
  58. #include <malloc.h>
  59. #include <mtdll.h>
  60. #include <stdlib.h>
  61. static void __cdecl _before(_PBLKDESC, size_t, _PBLKDESC, _PBLKDESC **);
  62. /***
  63. *int _heapadd(block, size) - Add a block of memory to the heap
  64. *
  65. *Purpose:
  66. * Add a block of user memory the heap.
  67. *
  68. * NOTE: The reason for the level of indirection between _heapadd
  69. * and _heap_addblock is (1) to validate the input, and (2) for
  70. * mthread locking/unlocking purposes.
  71. *
  72. * NOTE: _heapadd() DOES NOT enter the block of memory into the region
  73. * table! This is the cleanest way to avoid nasty bugs such as attempting
  74. * to grow, shrink or free static memory (e.g., a block that started out
  75. * being a static array). If the memory block does in fact belong in the
  76. * region table, it is the caller's responsibility to do it (internal
  77. * routines only, user programs should NEVER do this).
  78. *
  79. *Entry:
  80. * void * block = block of memory
  81. * size_t size = size of memory block
  82. *
  83. *Exit:
  84. * 0 = success
  85. * -1 = failure
  86. *
  87. *Exceptions:
  88. *
  89. *******************************************************************************/
  90. int __cdecl _heapadd (
  91. void * block,
  92. size_t size
  93. )
  94. {
  95. int retval;
  96. /*
  97. * Validate user's input. Note that _GRANULARITY must be a power
  98. * of 2 for the tests below to be valid!
  99. */
  100. if ( (size == 0) ||
  101. ((unsigned)block & (_GRANULARITY - 1)) ||
  102. (size & (_GRANULARITY - 1))
  103. )
  104. return(-1);
  105. /*
  106. * Add the block to the heap.
  107. */
  108. _mlock(_HEAP_LOCK);
  109. retval = _heap_addblock(block, size);
  110. _munlock(_HEAP_LOCK);
  111. return(retval);
  112. }
  113. /***
  114. *int _heap_addblock(block, size) - Add a block of memory to the heap
  115. *
  116. *Purpose:
  117. * Add a block of memory to the heap.
  118. *
  119. * Notes:
  120. * (1) Must handle case where new memory is already in heap
  121. * (i.e., could be the address of a previous 'dummy' entry).
  122. *
  123. *Entry:
  124. * void * block = address of memory block
  125. * size_t size = size of memory block
  126. *
  127. *Exit:
  128. * 0 = success
  129. * -1 = failure
  130. *
  131. *Exceptions:
  132. *
  133. *******************************************************************************/
  134. int __cdecl _heap_addblock (
  135. void * block,
  136. size_t size
  137. )
  138. {
  139. _PBLKDESC pdesc;
  140. REG1 _PBLKDESC pnewdesc;
  141. _PBLKDESC pdescs[4] = { NULL, NULL, NULL, NULL };
  142. _PBLKDESC *ppdesc = pdescs;
  143. size_t lastsize;
  144. int find;
  145. /*
  146. * Make sure we enough empty descriptors to do the job! Do it here
  147. * and now because recovering from an out-of-descriptors condition
  148. * is too dicey later on.
  149. */
  150. if ( ((pdescs[0] = __getempty()) == NULL) ||
  151. ((pdescs[1] = __getempty()) == NULL) ||
  152. ((pdescs[2] = __getempty()) == NULL) )
  153. {
  154. goto error;
  155. }
  156. /*
  157. * Find where the address fits into the heap.
  158. */
  159. find = _heap_findaddr(block, &pdesc);
  160. /*
  161. * Fill in the new heap descriptor.
  162. * (1) If the new address is an exact fit, use the dummy
  163. * descriptor that already exists for it.
  164. * (2) If the address is NOT in the heap, allocate a new one.
  165. */
  166. if ( find == _HEAPFIND_EXACT ) {
  167. if ( !(_IS_DUMMY(pdesc)) )
  168. goto error;
  169. pnewdesc = pdesc;
  170. }
  171. else {
  172. pnewdesc = *(ppdesc++);
  173. }
  174. pnewdesc->pblock = block; /* pointer to block */
  175. _SET_FREE(pnewdesc); /* set me free (why don't ya, babe) */
  176. *(_PBLKDESC*)block = pnewdesc; /* init back pointer */
  177. /*
  178. * Put the block in the heap
  179. * find = result of _heap_findaddr() call
  180. * pnewdesc = points to desc to be inserted
  181. * pdesc = filled in by _heap_findaddr() call as appropriate
  182. */
  183. switch (find) {
  184. case(_HEAPFIND_EMPTY):
  185. /*
  186. * No memory in heap yet
  187. */
  188. _heap_desc.sentinel.pblock = (char *) block + size;
  189. _before(pnewdesc, size, &_heap_desc.sentinel,
  190. &ppdesc);
  191. _heap_desc.pfirstdesc = _heap_desc.proverdesc =
  192. pnewdesc;
  193. break;
  194. case(_HEAPFIND_BEFORE):
  195. /*
  196. * New block is before the heap
  197. */
  198. _before(pnewdesc, size, _heap_desc.pfirstdesc,
  199. &ppdesc);
  200. _heap_desc.pfirstdesc = pnewdesc;
  201. break;
  202. case(_HEAPFIND_AFTER):
  203. /*
  204. * New block is after the heap
  205. *
  206. * Find the current last block in the heap
  207. */
  208. if ( _heap_findaddr((void *)((char *)
  209. (_heap_desc.sentinel.pblock) - 1), &pdesc) !=
  210. _HEAPFIND_WITHIN )
  211. _heap_abort();
  212. lastsize = _MEMSIZE(pdesc);
  213. /*
  214. * Start insertion by placing new block immediately
  215. * in front of the sentinel
  216. */
  217. _heap_desc.sentinel.pblock = (char *) block + size;
  218. pnewdesc->pnextdesc = &_heap_desc.sentinel;
  219. /*
  220. * Finish insertion by placing new block after the
  221. * old last block (with a possible intervening dummy
  222. * block being created)
  223. */
  224. _before(pdesc, lastsize, pnewdesc,
  225. &ppdesc);
  226. break;
  227. case(_HEAPFIND_EXACT):
  228. /*
  229. * Block is already in the heap (and we've checked
  230. * that it was a "dummy" before this call).
  231. *
  232. * [NOTES: (1) pnewdesc and pdesc are the same,
  233. * (2) pnewdesc is already linked to the previous
  234. * heap entry, (3) pdesc->pnextdesc is still valid!
  235. * (4) Also, if pdesc->pnextdesc is the sentinel,
  236. * then simply update the sentinel size (calling
  237. * before will cause an error if the previous last
  238. * block was bigger than the current one!).
  239. * (see code at top of this routine).]
  240. */
  241. if (pdesc->pnextdesc == &_heap_desc.sentinel)
  242. _heap_desc.sentinel.pblock =
  243. (char *) _ADDRESS(pdesc) + size;
  244. else
  245. _before(pnewdesc, size, pdesc->pnextdesc,
  246. &ppdesc);
  247. break;
  248. #ifdef DEBUG
  249. case(_HEAPFIND_WITHIN):
  250. #else
  251. default:
  252. #endif
  253. /*
  254. * New block is within heap
  255. */
  256. if (!(_IS_DUMMY(pdesc)))
  257. goto error;
  258. /*
  259. * If the last block in the heap is a dummy region
  260. * and a new region is allocated which lies within
  261. * that region, we need to update sentinel.pblock.
  262. */
  263. if (pdesc->pnextdesc == &_heap_desc.sentinel)
  264. {
  265. void * newend = (char *) _ADDRESS(pnewdesc) + size;
  266. if (_heap_desc.sentinel.pblock < newend)
  267. _heap_desc.sentinel.pblock = newend;
  268. }
  269. _before(pnewdesc, size, pdesc->pnextdesc,
  270. &ppdesc);
  271. _before(pdesc, _MEMSIZE(pdesc), pnewdesc,
  272. &ppdesc);
  273. break;
  274. #ifdef DEBUG
  275. /*
  276. * Return value unknown -- abort!
  277. */
  278. default:
  279. _heap_abort();
  280. #endif
  281. }
  282. /*
  283. * Update rover, if appropriate
  284. */
  285. if ( (block < _ADDRESS(_heap_desc.proverdesc)) &&
  286. (_BLKSIZE(pnewdesc) >= _heap_resetsize) )
  287. _heap_desc.proverdesc = pnewdesc;
  288. /*
  289. * Good return
  290. */
  291. /* good: unreferenced label to be removed */
  292. return(0);
  293. /*
  294. * Error return
  295. */
  296. error:
  297. while ( *ppdesc != NULL ) {
  298. _PUTEMPTY(*ppdesc);
  299. ppdesc++;
  300. }
  301. return(-1);
  302. }
  303. /***
  304. *static void _before(pdesc1, size, pdesc2, pppdesc) - Insert a block before
  305. * a supplied descriptor
  306. *
  307. *Purpose:
  308. * This routine inserts a new descriptor before another descriptor.
  309. *
  310. * Notes:
  311. * (1) A dummy descriptor will be inserted into the heap as
  312. * necessary.
  313. * (2) This routine only updates FORWARD links. Call this
  314. * routine twice to update links in both directions.
  315. *
  316. *Entry:
  317. * _PBLKDESC pdesc1 = new descriptor to insert in the heap
  318. * size_t size = size of pdesc1 block
  319. * _PBLKDESC pdesc2 = descriptor before which block should go
  320. * _PBLKDESC **pppdesc = pointer to a pointer to the list of pointers
  321. * of empty descriptors
  322. *
  323. *Exit:
  324. * (void)
  325. *
  326. *Exceptions:
  327. *
  328. *******************************************************************************/
  329. static void __cdecl _before (
  330. REG1 _PBLKDESC pdesc1,
  331. size_t size,
  332. REG2 _PBLKDESC pdesc2,
  333. _PBLKDESC **pppdesc
  334. )
  335. {
  336. size_t diff;
  337. _PBLKDESC pdummydesc;
  338. void * dummyaddr;
  339. /*
  340. * Check for dummy descriptors:
  341. * (1) If first block is dummy, no adjustement needed.
  342. * (2) If second block is dummy, simply adjust size.
  343. */
  344. if (_IS_DUMMY(pdesc1))
  345. goto link;
  346. if (_IS_DUMMY(pdesc2)) {
  347. pdesc2->pblock = (char *)_ADDRESS(pdesc1) + size;
  348. _SET_DUMMY(pdesc2);
  349. goto link;
  350. }
  351. /*
  352. * See how much space is between this block and the next one.
  353. */
  354. diff = ( (char *) _ADDRESS(pdesc2) -
  355. (char *) (dummyaddr = (char *) _ADDRESS(pdesc1) + size) );
  356. if (diff != 0) {
  357. #ifdef DEBUG
  358. /*
  359. * Internal bogosity check
  360. */
  361. if ((int)diff < 0)
  362. _heap_abort();
  363. #endif
  364. /*
  365. * There is some space between the two blocks. Insert
  366. * a fake "in use" block. Remember, there is no 'back
  367. * pointer' in dummy blocks.
  368. */
  369. pdummydesc = *((*pppdesc)++);
  370. pdummydesc->pblock = (char *) dummyaddr;
  371. _SET_DUMMY(pdummydesc);
  372. pdesc1->pnextdesc = pdummydesc;
  373. pdesc1 = pdummydesc;
  374. }
  375. /*
  376. * Put the new block in the heap.
  377. */
  378. link:
  379. pdesc1->pnextdesc = pdesc2;
  380. }
  381. #endif /* WINHEAP */