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.

402 lines
10 KiB

  1. /*** heap.c - Heap memory management functions
  2. *
  3. * Copyright (c) 1996,1997 Microsoft Corporation
  4. * Author: Michael Tsang (MikeTs)
  5. * Created 07/14/97
  6. *
  7. * MODIFICATION HISTORY
  8. */
  9. #include "pch.h"
  10. #ifdef LOCKABLE_PRAGMA
  11. #pragma ACPI_LOCKABLE_DATA
  12. #pragma ACPI_LOCKABLE_CODE
  13. #endif
  14. /***LP NewHeap - create a new heap block
  15. *
  16. * ENTRY
  17. * dwLen - heap length
  18. * ppheap -> to hold the newly created heap
  19. *
  20. * EXIT-SUCCESS
  21. * returns STATUS_SUCCESS
  22. * EXIT-FAILURE
  23. * returns AMLIERR_ code
  24. */
  25. NTSTATUS LOCAL NewHeap(ULONG dwLen, PHEAP *ppheap)
  26. {
  27. TRACENAME("NEWHEAP")
  28. NTSTATUS rc = STATUS_SUCCESS;
  29. ENTER(3, ("NewHeap(HeapLen=%d,ppheap=%x)\n", dwLen, ppheap));
  30. if ((*ppheap = NEWHPOBJ(dwLen)) == NULL)
  31. {
  32. rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
  33. ("NewHeap: failed to allocate new heap block"));
  34. }
  35. else
  36. {
  37. InitHeap(*ppheap, dwLen);
  38. }
  39. EXIT(3, ("NewHeap=%x (pheap=%x)\n", rc, *ppheap));
  40. return rc;
  41. } //NewHeap
  42. /***LP FreeHeap - free the heap block
  43. *
  44. * ENTRY
  45. * pheap -> HEAP
  46. *
  47. * EXIT
  48. * None
  49. */
  50. VOID LOCAL FreeHeap(PHEAP pheap)
  51. {
  52. TRACENAME("FREEHEAP")
  53. ENTER(2, ("FreeHeap(pheap=%x)\n", pheap));
  54. FREEHPOBJ(pheap);
  55. EXIT(2, ("FreeHeap!\n"));
  56. } //FreeHeap
  57. /***LP InitHeap - initialize a given heap block
  58. *
  59. * ENTRY
  60. * pheap -> HEAP
  61. * dwLen - length of heap block
  62. *
  63. * EXIT
  64. * None
  65. */
  66. VOID LOCAL InitHeap(PHEAP pheap, ULONG dwLen)
  67. {
  68. TRACENAME("INITHEAP")
  69. ENTER(3, ("InitHeap(pheap=%x,Len=%d)\n", pheap, dwLen));
  70. MEMZERO(pheap, dwLen);
  71. pheap->dwSig = SIG_HEAP;
  72. pheap->pbHeapEnd = (PUCHAR)pheap + dwLen;
  73. pheap->pbHeapTop = (PUCHAR)&pheap->Heap;
  74. EXIT(3, ("InitHeap!\n"));
  75. } //InitHeap
  76. /***LP HeapAlloc - allocate a memory block from a given heap
  77. *
  78. * ENTRY
  79. * pheapHead -> HEAP
  80. * dwSig - signature of the block to be allocated
  81. * dwLen - length of block to be allocated
  82. *
  83. * EXIT-SUCCESS
  84. * returns pointer to allocated memory
  85. * EXIT-FAILURE
  86. * returns NULL
  87. */
  88. PVOID LOCAL HeapAlloc(PHEAP pheapHead, ULONG dwSig, ULONG dwLen)
  89. {
  90. TRACENAME("HEAPALLOC")
  91. PHEAPOBJHDR phobj = NULL;
  92. PHEAP pheapPrev = NULL, pheap = NULL;
  93. ENTER(3, ("HeapAlloc(pheapHead=%x,Sig=%s,Len=%d)\n",
  94. pheapHead, NameSegString(dwSig), dwLen));
  95. ASSERT(pheapHead != NULL);
  96. ASSERT(pheapHead->dwSig == SIG_HEAP);
  97. ASSERT(pheapHead->pheapHead != NULL);
  98. ASSERT(pheapHead == pheapHead->pheapHead);
  99. dwLen += sizeof(HEAPOBJHDR) - sizeof(LIST);
  100. if (dwLen < sizeof(HEAPOBJHDR))
  101. {
  102. //
  103. // Minimum allocated size has to be HEAPOBJHDR size.
  104. //
  105. dwLen = sizeof(HEAPOBJHDR);
  106. }
  107. //
  108. // Round it up to the proper alignment.
  109. //
  110. dwLen += DEF_HEAP_ALIGNMENT - 1;
  111. dwLen &= ~(DEF_HEAP_ALIGNMENT - 1);
  112. AcquireMutex(&gmutHeap);
  113. if (dwLen <= PtrToUlong(pheapHead->pbHeapEnd) - PtrToUlong(&pheapHead->Heap))
  114. {
  115. for (pheap = pheapHead; pheap != NULL; pheap = pheap->pheapNext)
  116. {
  117. if ((phobj = HeapFindFirstFit(pheap, dwLen)) != NULL)
  118. {
  119. ASSERT(phobj->dwSig == 0);
  120. ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap);
  121. if (phobj->dwLen >= dwLen + sizeof(HEAPOBJHDR))
  122. {
  123. PHEAPOBJHDR phobjNext = (PHEAPOBJHDR)((PUCHAR)phobj + dwLen);
  124. phobjNext->dwSig = 0;
  125. phobjNext->dwLen = phobj->dwLen - dwLen;
  126. phobjNext->pheap = pheap;
  127. phobj->dwLen = dwLen;
  128. HeapInsertFreeList(pheap, phobjNext);
  129. }
  130. break;
  131. }
  132. else if (dwLen <= (ULONG)(pheap->pbHeapEnd - pheap->pbHeapTop))
  133. {
  134. phobj = (PHEAPOBJHDR)pheap->pbHeapTop;
  135. pheap->pbHeapTop += dwLen;
  136. phobj->dwLen = dwLen;
  137. break;
  138. }
  139. else
  140. {
  141. pheapPrev = pheap;
  142. }
  143. }
  144. //
  145. // If we are running out of Global Heap space, we will dynamically
  146. // extend it.
  147. //
  148. if ((phobj == NULL) && (pheapHead == gpheapGlobal) &&
  149. (NewHeap(gdwGlobalHeapBlkSize, &pheap) == STATUS_SUCCESS))
  150. {
  151. pheap->pheapHead = pheapHead;
  152. pheapPrev->pheapNext = pheap;
  153. ASSERT(dwLen <= PtrToUlong(pheap->pbHeapEnd) - PtrToUlong(&pheap->Heap));
  154. phobj = (PHEAPOBJHDR)pheap->pbHeapTop;
  155. pheap->pbHeapTop += dwLen;
  156. phobj->dwLen = dwLen;
  157. }
  158. if (phobj != NULL)
  159. {
  160. #ifdef DEBUG
  161. if (pheapHead == gpheapGlobal)
  162. {
  163. KIRQL oldIrql;
  164. KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql );
  165. gdwGlobalHeapSize += phobj->dwLen;
  166. KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql );
  167. }
  168. else
  169. {
  170. ULONG dwTotalHeap = 0;
  171. PHEAP ph;
  172. for (ph = pheapHead; ph != NULL; ph = ph->pheapNext)
  173. {
  174. dwTotalHeap += (ULONG)((ULONG_PTR)ph->pbHeapTop -
  175. (ULONG_PTR)&ph->Heap);
  176. }
  177. if (dwTotalHeap > gdwLocalHeapMax)
  178. {
  179. gdwLocalHeapMax = dwTotalHeap;
  180. }
  181. }
  182. #endif
  183. phobj->dwSig = dwSig;
  184. phobj->pheap = pheap;
  185. MEMZERO(&phobj->list, dwLen - (sizeof(HEAPOBJHDR) - sizeof(LIST)));
  186. }
  187. }
  188. ReleaseMutex(&gmutHeap);
  189. EXIT(3, ("HeapAlloc=%x (pheap=%x)\n", phobj? &phobj->list: NULL, pheap));
  190. return phobj? &phobj->list: NULL;
  191. } //HeapAlloc
  192. /***LP HeapFree - free a memory block
  193. *
  194. * ENTRY
  195. * pb -> memory block
  196. *
  197. * EXIT
  198. * None
  199. */
  200. VOID LOCAL HeapFree(PVOID pb)
  201. {
  202. TRACENAME("HEAPFREE")
  203. PHEAPOBJHDR phobj;
  204. ASSERT(pb != NULL);
  205. phobj = CONTAINING_RECORD(pb, HEAPOBJHDR, list);
  206. ENTER(3, ("HeapFree(pheap=%x,pb=%x,Sig=%s,Len=%d)\n",
  207. phobj->pheap, pb, NameSegString(phobj->dwSig), phobj->dwLen));
  208. ASSERT((phobj >= &phobj->pheap->Heap) &&
  209. ((PUCHAR)phobj + phobj->dwLen <= phobj->pheap->pbHeapEnd));
  210. ASSERT(phobj->dwSig != 0);
  211. if ((pb != NULL) && (phobj->dwSig != 0))
  212. {
  213. #ifdef DEBUG
  214. if (phobj->pheap->pheapHead == gpheapGlobal)
  215. {
  216. KIRQL oldIrql;
  217. KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql );
  218. gdwGlobalHeapSize -= phobj->dwLen;
  219. KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql );
  220. }
  221. #endif
  222. phobj->dwSig = 0;
  223. AcquireMutex(&gmutHeap);
  224. HeapInsertFreeList(phobj->pheap, phobj);
  225. ReleaseMutex(&gmutHeap);
  226. }
  227. EXIT(3, ("HeapFree!\n"));
  228. } //HeapFree
  229. /***LP HeapFindFirstFit - find first fit free object
  230. *
  231. * ENTRY
  232. * pheap -> HEAP
  233. * dwLen - size of object
  234. *
  235. * EXIT-SUCCESS
  236. * returns the object
  237. * EXIT-FAILURE
  238. * returns NULL
  239. */
  240. PHEAPOBJHDR LOCAL HeapFindFirstFit(PHEAP pheap, ULONG dwLen)
  241. {
  242. TRACENAME("HEAPFINDFIRSTFIT")
  243. PHEAPOBJHDR phobj = NULL;
  244. ENTER(3, ("HeapFindFirstFit(pheap=%x,Len=%d)\n", pheap, dwLen));
  245. if (pheap->plistFreeHeap != NULL)
  246. {
  247. PLIST plist = pheap->plistFreeHeap;
  248. do
  249. {
  250. phobj = CONTAINING_RECORD(plist, HEAPOBJHDR, list);
  251. if (dwLen <= phobj->dwLen)
  252. {
  253. break;
  254. }
  255. else
  256. {
  257. plist = plist->plistNext;
  258. }
  259. } while (plist != pheap->plistFreeHeap);
  260. if (dwLen > phobj->dwLen)
  261. {
  262. phobj = NULL;
  263. }
  264. }
  265. EXIT(3, ("HeapFindFirstFit=%x (Len=%d)\n", phobj, phobj? phobj->dwLen: 0));
  266. return phobj;
  267. } //HeapFindFirstFit
  268. /***LP HeapInsertFreeList - insert heap object into free list
  269. *
  270. * ENTRY
  271. * pheap -> HEAP
  272. * phobj -> heap object
  273. *
  274. * EXIT
  275. * None
  276. */
  277. VOID LOCAL HeapInsertFreeList(PHEAP pheap, PHEAPOBJHDR phobj)
  278. {
  279. TRACENAME("HEAPINSERTFREELIST")
  280. PHEAPOBJHDR phobj1;
  281. ENTER(3, ("HeapInsertFreeList(pheap=%x,phobj=%x)\n", pheap, phobj))
  282. ASSERT(phobj->dwLen >= sizeof(HEAPOBJHDR));
  283. if (pheap->plistFreeHeap != NULL)
  284. {
  285. PLIST plist = pheap->plistFreeHeap;
  286. do
  287. {
  288. if (&phobj->list < plist)
  289. {
  290. break;
  291. }
  292. else
  293. {
  294. plist = plist->plistNext;
  295. }
  296. } while (plist != pheap->plistFreeHeap);
  297. if (&phobj->list < plist)
  298. {
  299. phobj->list.plistNext = plist;
  300. phobj->list.plistPrev = plist->plistPrev;
  301. phobj->list.plistPrev->plistNext = &phobj->list;
  302. phobj->list.plistNext->plistPrev = &phobj->list;
  303. if (pheap->plistFreeHeap == plist)
  304. {
  305. pheap->plistFreeHeap = &phobj->list;
  306. }
  307. }
  308. else
  309. {
  310. ListInsertTail(&phobj->list, &pheap->plistFreeHeap);
  311. }
  312. }
  313. else
  314. {
  315. ListInsertHead(&phobj->list, &pheap->plistFreeHeap);
  316. }
  317. //
  318. // Check if the next adjacent block is free. If so, coalesce it.
  319. //
  320. phobj1 = (PHEAPOBJHDR)((PUCHAR)phobj + phobj->dwLen);
  321. if (phobj->list.plistNext == &phobj1->list)
  322. {
  323. ASSERT(phobj1->dwSig == 0);
  324. phobj->dwLen += phobj1->dwLen;
  325. ListRemoveEntry(&phobj1->list, &pheap->plistFreeHeap);
  326. }
  327. //
  328. // Check if the previous adjacent block is free. If so, coalesce it.
  329. //
  330. phobj1 = CONTAINING_RECORD(phobj->list.plistPrev, HEAPOBJHDR, list);
  331. if ((PUCHAR)phobj1 + phobj1->dwLen == (PUCHAR)phobj)
  332. {
  333. ASSERT(phobj1->dwSig == 0);
  334. phobj1->dwLen += phobj->dwLen;
  335. ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap);
  336. phobj = phobj1;
  337. }
  338. if ((PUCHAR)phobj + phobj->dwLen >= pheap->pbHeapTop)
  339. {
  340. pheap->pbHeapTop = (PUCHAR)phobj;
  341. ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap);
  342. }
  343. EXIT(3, ("HeapInsertFreeList!\n"));
  344. } //HeapInsertFreeList