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.

364 lines
7.1 KiB

  1. //============================================================================
  2. // Copyright (c) 1996, Microsoft Corporation
  3. //
  4. // File: mm.c
  5. //
  6. // History:
  7. // Abolade Gbadegesin Jan-226-1996 Created.
  8. //
  9. // Contains code for memory management in IPRIP
  10. //============================================================================
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <rtutils.h>
  16. #include "mm.h"
  17. // Function: MmHeapCreate
  18. //
  19. // This function creates a heap and initializes lists which will contain
  20. // the addresses of allocated and freed blocks of memory.
  21. HANDLE
  22. MmHeapCreate(
  23. DWORD dwInitialSize,
  24. DWORD dwMaximumSize
  25. ) {
  26. DWORD dwErr;
  27. HANDLE hHeap;
  28. MMHEAP *pheap;
  29. //
  30. // create a Win32 heap; we specify no serialization
  31. // since our critical section will enforce serialization
  32. //
  33. hHeap = HeapCreate(HEAP_NO_SERIALIZE, dwInitialSize, dwMaximumSize);
  34. if (hHeap == NULL) { return NULL; }
  35. //
  36. // within the heap created, allocate space for the managed heap
  37. //
  38. pheap = HeapAlloc(hHeap, 0, sizeof(MMHEAP));
  39. if (pheap == NULL) {
  40. dwErr = GetLastError();
  41. HeapDestroy(hHeap);
  42. SetLastError(dwErr);
  43. return NULL;
  44. }
  45. //
  46. // initialize the managed heap
  47. //
  48. pheap->hHeap = hHeap;
  49. InitializeListHead(&pheap->lhFreeList);
  50. InitializeListHead(&pheap->lhBusyList);
  51. InitializeCriticalSection(&pheap->csListLock);
  52. //
  53. // return a pointer to the managed heap structure
  54. //
  55. return (HANDLE)pheap;
  56. }
  57. // Function: MmHeapDestroy
  58. //
  59. // This function destroys a heap.
  60. BOOL
  61. MmHeapDestroy(
  62. HANDLE hHeap
  63. ) {
  64. MMHEAP *pheap;
  65. pheap = (MMHEAP *)hHeap;
  66. //
  67. // delete the lists' synchronization object
  68. //
  69. DeleteCriticalSection(&pheap->csListLock);
  70. //
  71. // a managed heap can be destroyed by merely destroying the heap
  72. // which was initially created for the managed heap, since all
  73. // allocations came out of that heap
  74. //
  75. return HeapDestroy(pheap->hHeap);
  76. }
  77. // Function: MmHeapAlloc
  78. //
  79. // This function makes an allocation from a managed heap
  80. PVOID
  81. MmHeapAlloc(
  82. HANDLE hHeap,
  83. DWORD dwBytes
  84. ) {
  85. INT cmp;
  86. DWORD dwErr;
  87. MMHEAP *pheap;
  88. MMHEADER *phdr;
  89. LIST_ENTRY *ple, *phead;
  90. if (!hHeap || !dwBytes) { return NULL; }
  91. pheap = (MMHEAP *)hHeap;
  92. EnterCriticalSection(&pheap->csListLock);
  93. //
  94. // search the free-list for the allocation which
  95. // is closest in size to the number of bytes requested
  96. //
  97. phdr = NULL;
  98. phead = &pheap->lhFreeList;
  99. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  100. phdr = CONTAINING_RECORD(ple, MMHEADER, leLink);
  101. cmp = (dwBytes - phdr->dwBlockSize);
  102. if (cmp < 0) { continue; }
  103. else
  104. if (cmp > 0) { break; }
  105. //
  106. // the entry found is precisely the required size;
  107. //
  108. break;
  109. }
  110. //
  111. // if a re-usable entry was found, reset its timestamp,
  112. // move it to the busy-list, and return a pointer past the header.
  113. // otherwise, allocate a new entry for the caller,
  114. // initialize it, place it on the busy-list, and return a pointer.
  115. //
  116. if (ple != phead) {
  117. //
  118. // a re-usable entry was found
  119. //
  120. RemoveEntryList(&phdr->leLink);
  121. }
  122. else {
  123. //
  124. // no re-usable entry was found, allocate a new one
  125. //
  126. phdr = HeapAlloc(
  127. pheap->hHeap, HEAP_NO_SERIALIZE, dwBytes + sizeof(MMHEADER)
  128. );
  129. if (!phdr) {
  130. dwErr = GetLastError();
  131. LeaveCriticalSection(&pheap->csListLock);
  132. SetLastError(dwErr);
  133. return NULL;
  134. }
  135. }
  136. //
  137. // set the entry's timestamp and put it on the busy list
  138. //
  139. NtQuerySystemTime(&phdr->liTimeStamp);
  140. InsertHeadList(&pheap->lhBusyList, &phdr->leLink);
  141. LeaveCriticalSection(&pheap->csListLock);
  142. return (PVOID)(phdr + 1);
  143. }
  144. // Function: MmHeapFree
  145. //
  146. // This function frees an allocation made by MmHeapAlloc
  147. BOOL
  148. MmHeapFree(
  149. HANDLE hHeap,
  150. PVOID pMem
  151. ) {
  152. INT cmp;
  153. MMHEAP *pheap;
  154. MMHEADER *phdr, *phdrFree;
  155. LIST_ENTRY *ple, *phead;
  156. if (!hHeap || !pMem) { return FALSE; }
  157. pheap = (MMHEAP *)hHeap;
  158. EnterCriticalSection(&pheap->csListLock);
  159. phdr = (MMHEADER *)((PBYTE)pMem - sizeof(MMHEADER));
  160. //
  161. // remove the entry from the busy-list
  162. //
  163. RemoveEntryList(&phdr->leLink);
  164. //
  165. // place the entry on the free-list,
  166. // which is in order of ascending size (smallest-first)
  167. //
  168. phead = &pheap->lhFreeList;
  169. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  170. phdrFree = CONTAINING_RECORD(ple, MMHEADER, leLink);
  171. cmp = (phdr->dwBlockSize - phdrFree->dwBlockSize);
  172. if (cmp < 0) { break; }
  173. else
  174. if (cmp > 0) { continue; }
  175. //
  176. // the allocations are the same size, but the newly-free one
  177. // is most likely the most-recently active
  178. //
  179. break;
  180. }
  181. //
  182. // insert the newly-free entry before the one found
  183. // (since this is a circular list, we accomplish this
  184. // using InsertTailList; think about it a while.)
  185. //
  186. NtQuerySystemTime(&phdr->liTimeStamp);
  187. InsertTailList(ple, &phdr->leLink);
  188. LeaveCriticalSection(&pheap->csListLock);
  189. return TRUE;
  190. }
  191. // Function: MmHeapCollectGarbage
  192. //
  193. // This function is called by the owner of the heap.
  194. // It takes as its argument an interval I in systime-units
  195. // (system-time is measured in 100-nanosecond units), and any allocations
  196. // on the free list which have not been re-used in the past I systime-units
  197. // are returned to the Win32 heap.
  198. //
  199. // To return all free entries to the Win32 heap, specify an interval of 0.
  200. BOOL
  201. MmHeapCollectGarbage(
  202. HANDLE hHeap,
  203. LARGE_INTEGER liInterval
  204. ) {
  205. INT cmp;
  206. MMHEAP *pheap;
  207. MMHEADER *phdr;
  208. LIST_ENTRY *ple, *phead;
  209. LARGE_INTEGER liCutoff;
  210. if (!hHeap) { return FALSE; }
  211. pheap = (MMHEAP *)hHeap;
  212. EnterCriticalSection(&pheap->csListLock);
  213. //
  214. // get the current system-time, and from that compute the cutoff-time
  215. // for allocation timestamps, by subtracting the interval passed in
  216. // to get the time of the earliest allocation which can be exempt
  217. // from garbage-collection
  218. //
  219. NtQuerySystemTime(&liCutoff);
  220. liCutoff = RtlLargeIntegerSubtract(liCutoff, liInterval);
  221. //
  222. // go through the free-list
  223. //
  224. phead = &pheap->lhFreeList;
  225. for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
  226. phdr = CONTAINING_RECORD(ple, MMHEADER, leLink);
  227. if (RtlLargeIntegerLessThan(liCutoff, phdr->liTimeStamp)) { continue; }
  228. //
  229. // this allocation is stamped from before the cutoff interval,
  230. // so we'll have to free it (with care, since it is a link
  231. // in the list we are walking through).
  232. //
  233. ple = ple->Blink;
  234. RemoveEntryList(&phdr->leLink);
  235. HeapFree(pheap->hHeap, HEAP_NO_SERIALIZE, phdr);
  236. }
  237. LeaveCriticalSection(&pheap->csListLock);
  238. return TRUE;
  239. }