Leaked source code of windows server 2003
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.

403 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. ASSERT( pheapPrev != NULL );
  153. pheapPrev->pheapNext = pheap;
  154. ASSERT(dwLen <= PtrToUlong(pheap->pbHeapEnd) - PtrToUlong(&pheap->Heap));
  155. phobj = (PHEAPOBJHDR)pheap->pbHeapTop;
  156. pheap->pbHeapTop += dwLen;
  157. phobj->dwLen = dwLen;
  158. }
  159. if (phobj != NULL)
  160. {
  161. #ifdef DEBUG
  162. if (pheapHead == gpheapGlobal)
  163. {
  164. KIRQL oldIrql;
  165. KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql );
  166. gdwGlobalHeapSize += phobj->dwLen;
  167. KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql );
  168. }
  169. else
  170. {
  171. ULONG dwTotalHeap = 0;
  172. PHEAP ph;
  173. for (ph = pheapHead; ph != NULL; ph = ph->pheapNext)
  174. {
  175. dwTotalHeap += (ULONG)((ULONG_PTR)ph->pbHeapTop -
  176. (ULONG_PTR)&ph->Heap);
  177. }
  178. if (dwTotalHeap > gdwLocalHeapMax)
  179. {
  180. gdwLocalHeapMax = dwTotalHeap;
  181. }
  182. }
  183. #endif
  184. phobj->dwSig = dwSig;
  185. phobj->pheap = pheap;
  186. MEMZERO(&phobj->list, dwLen - (sizeof(HEAPOBJHDR) - sizeof(LIST)));
  187. }
  188. }
  189. ReleaseMutex(&gmutHeap);
  190. EXIT(3, ("HeapAlloc=%x (pheap=%x)\n", phobj? &phobj->list: NULL, pheap));
  191. return phobj? &phobj->list: NULL;
  192. } //HeapAlloc
  193. /***LP HeapFree - free a memory block
  194. *
  195. * ENTRY
  196. * pb -> memory block
  197. *
  198. * EXIT
  199. * None
  200. */
  201. VOID LOCAL HeapFree(PVOID pb)
  202. {
  203. TRACENAME("HEAPFREE")
  204. PHEAPOBJHDR phobj;
  205. ASSERT(pb != NULL);
  206. phobj = CONTAINING_RECORD(pb, HEAPOBJHDR, list);
  207. ENTER(3, ("HeapFree(pheap=%x,pb=%x,Sig=%s,Len=%d)\n",
  208. phobj->pheap, pb, NameSegString(phobj->dwSig), phobj->dwLen));
  209. ASSERT((phobj >= &phobj->pheap->Heap) &&
  210. ((PUCHAR)phobj + phobj->dwLen <= phobj->pheap->pbHeapEnd));
  211. ASSERT(phobj->dwSig != 0);
  212. if ((pb != NULL) && (phobj->dwSig != 0))
  213. {
  214. #ifdef DEBUG
  215. if (phobj->pheap->pheapHead == gpheapGlobal)
  216. {
  217. KIRQL oldIrql;
  218. KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql );
  219. gdwGlobalHeapSize -= phobj->dwLen;
  220. KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql );
  221. }
  222. #endif
  223. phobj->dwSig = 0;
  224. AcquireMutex(&gmutHeap);
  225. HeapInsertFreeList(phobj->pheap, phobj);
  226. ReleaseMutex(&gmutHeap);
  227. }
  228. EXIT(3, ("HeapFree!\n"));
  229. } //HeapFree
  230. /***LP HeapFindFirstFit - find first fit free object
  231. *
  232. * ENTRY
  233. * pheap -> HEAP
  234. * dwLen - size of object
  235. *
  236. * EXIT-SUCCESS
  237. * returns the object
  238. * EXIT-FAILURE
  239. * returns NULL
  240. */
  241. PHEAPOBJHDR LOCAL HeapFindFirstFit(PHEAP pheap, ULONG dwLen)
  242. {
  243. TRACENAME("HEAPFINDFIRSTFIT")
  244. PHEAPOBJHDR phobj = NULL;
  245. ENTER(3, ("HeapFindFirstFit(pheap=%x,Len=%d)\n", pheap, dwLen));
  246. if (pheap->plistFreeHeap != NULL)
  247. {
  248. PLIST plist = pheap->plistFreeHeap;
  249. do
  250. {
  251. phobj = CONTAINING_RECORD(plist, HEAPOBJHDR, list);
  252. if (dwLen <= phobj->dwLen)
  253. {
  254. break;
  255. }
  256. else
  257. {
  258. plist = plist->plistNext;
  259. }
  260. } while (plist != pheap->plistFreeHeap);
  261. if (dwLen > phobj->dwLen)
  262. {
  263. phobj = NULL;
  264. }
  265. }
  266. EXIT(3, ("HeapFindFirstFit=%x (Len=%d)\n", phobj, phobj? phobj->dwLen: 0));
  267. return phobj;
  268. } //HeapFindFirstFit
  269. /***LP HeapInsertFreeList - insert heap object into free list
  270. *
  271. * ENTRY
  272. * pheap -> HEAP
  273. * phobj -> heap object
  274. *
  275. * EXIT
  276. * None
  277. */
  278. VOID LOCAL HeapInsertFreeList(PHEAP pheap, PHEAPOBJHDR phobj)
  279. {
  280. TRACENAME("HEAPINSERTFREELIST")
  281. PHEAPOBJHDR phobj1;
  282. ENTER(3, ("HeapInsertFreeList(pheap=%x,phobj=%x)\n", pheap, phobj))
  283. ASSERT(phobj->dwLen >= sizeof(HEAPOBJHDR));
  284. if (pheap->plistFreeHeap != NULL)
  285. {
  286. PLIST plist = pheap->plistFreeHeap;
  287. do
  288. {
  289. if (&phobj->list < plist)
  290. {
  291. break;
  292. }
  293. else
  294. {
  295. plist = plist->plistNext;
  296. }
  297. } while (plist != pheap->plistFreeHeap);
  298. if (&phobj->list < plist)
  299. {
  300. phobj->list.plistNext = plist;
  301. phobj->list.plistPrev = plist->plistPrev;
  302. phobj->list.plistPrev->plistNext = &phobj->list;
  303. phobj->list.plistNext->plistPrev = &phobj->list;
  304. if (pheap->plistFreeHeap == plist)
  305. {
  306. pheap->plistFreeHeap = &phobj->list;
  307. }
  308. }
  309. else
  310. {
  311. ListInsertTail(&phobj->list, &pheap->plistFreeHeap);
  312. }
  313. }
  314. else
  315. {
  316. ListInsertHead(&phobj->list, &pheap->plistFreeHeap);
  317. }
  318. //
  319. // Check if the next adjacent block is free. If so, coalesce it.
  320. //
  321. phobj1 = (PHEAPOBJHDR)((PUCHAR)phobj + phobj->dwLen);
  322. if (phobj->list.plistNext == &phobj1->list)
  323. {
  324. ASSERT(phobj1->dwSig == 0);
  325. phobj->dwLen += phobj1->dwLen;
  326. ListRemoveEntry(&phobj1->list, &pheap->plistFreeHeap);
  327. }
  328. //
  329. // Check if the previous adjacent block is free. If so, coalesce it.
  330. //
  331. phobj1 = CONTAINING_RECORD(phobj->list.plistPrev, HEAPOBJHDR, list);
  332. if ((PUCHAR)phobj1 + phobj1->dwLen == (PUCHAR)phobj)
  333. {
  334. ASSERT(phobj1->dwSig == 0);
  335. phobj1->dwLen += phobj->dwLen;
  336. ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap);
  337. phobj = phobj1;
  338. }
  339. if ((PUCHAR)phobj + phobj->dwLen >= pheap->pbHeapTop)
  340. {
  341. pheap->pbHeapTop = (PUCHAR)phobj;
  342. ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap);
  343. }
  344. EXIT(3, ("HeapInsertFreeList!\n"));
  345. } //HeapInsertFreeList