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.

381 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1995-1999 Microsoft Corporation
  3. Module Name:
  4. chunk.c
  5. Abstract:
  6. This routine will manage allocations of chunks of structures
  7. Author:
  8. 16-Jan-1997 AlanWar
  9. Revision History:
  10. --*/
  11. #include "wmikmp.h"
  12. PENTRYHEADER WmipAllocEntry(
  13. PCHUNKINFO ChunkInfo
  14. );
  15. void WmipFreeEntry(
  16. PCHUNKINFO ChunkInfo,
  17. PENTRYHEADER Entry
  18. );
  19. ULONG WmipUnreferenceEntry(
  20. PCHUNKINFO ChunkInfo,
  21. PENTRYHEADER Entry
  22. );
  23. PWCHAR WmipCountedToSz(
  24. PWCHAR Counted
  25. );
  26. #if HEAPVALIDATION
  27. PVOID WmipAlloc(
  28. ULONG Size
  29. );
  30. void WmipFree(
  31. PVOID p
  32. );
  33. #endif
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGE,WmipAllocEntry)
  36. #pragma alloc_text(PAGE,WmipFreeEntry)
  37. #pragma alloc_text(PAGE,WmipUnreferenceEntry)
  38. #pragma alloc_text(PAGE,WmipCountedToSz)
  39. #if HEAPVALIDATION
  40. #pragma alloc_text(PAGE,WmipAllocWithTag)
  41. #pragma alloc_text(PAGE,WmipAlloc)
  42. #pragma alloc_text(PAGE,WmipFree)
  43. #endif
  44. #endif
  45. //
  46. // TODO: Use Ex lookaside lists instead of my own allocations
  47. //
  48. PENTRYHEADER WmipAllocEntry(
  49. PCHUNKINFO ChunkInfo
  50. )
  51. /*++
  52. Routine Description:
  53. This routine will allocate a single structure within a list of chunks
  54. of structures.
  55. Arguments:
  56. ChunkInfo describes the chunks of structures
  57. Return Value:
  58. Pointer to structure or NULL if one cannot be allocated. Entry returns
  59. with its refcount set to 1
  60. --*/
  61. {
  62. PLIST_ENTRY ChunkList, EntryList, FreeEntryHead;
  63. PCHUNKHEADER Chunk;
  64. PUCHAR EntryPtr;
  65. ULONG EntryCount, ChunkSize;
  66. PENTRYHEADER Entry;
  67. ULONG i;
  68. PAGED_CODE();
  69. WmipEnterSMCritSection();
  70. ChunkList = ChunkInfo->ChunkHead.Flink;
  71. //
  72. // Loop over all chunks to see if any chunk has a free entry for us
  73. while(ChunkList != &ChunkInfo->ChunkHead)
  74. {
  75. Chunk = CONTAINING_RECORD(ChunkList, CHUNKHEADER, ChunkList);
  76. if (! IsListEmpty(&Chunk->FreeEntryHead))
  77. {
  78. EntryList = RemoveHeadList(&Chunk->FreeEntryHead);
  79. Chunk->EntriesInUse++;
  80. WmipLeaveSMCritSection();
  81. Entry = (CONTAINING_RECORD(EntryList,
  82. ENTRYHEADER,
  83. FreeEntryList));
  84. WmipAssert(Entry->Flags & FLAG_ENTRY_ON_FREE_LIST);
  85. memset(Entry, 0, ChunkInfo->EntrySize);
  86. Entry->Chunk = Chunk;
  87. Entry->RefCount = 1;
  88. Entry->Flags = ChunkInfo->InitialFlags;
  89. Entry->Signature = ChunkInfo->Signature;
  90. #if DBG
  91. InterlockedIncrement(&ChunkInfo->AllocCount);
  92. #endif
  93. return(Entry);
  94. }
  95. ChunkList = ChunkList->Flink;
  96. }
  97. WmipLeaveSMCritSection();
  98. //
  99. // There are no more free entries in any of the chunks. Allocate a new
  100. // chunk if we can
  101. ChunkSize = (ChunkInfo->EntrySize * ChunkInfo->EntriesPerChunk) +
  102. sizeof(CHUNKHEADER);
  103. Chunk = (PCHUNKHEADER)ExAllocatePoolWithTag(PagedPool,
  104. ChunkSize,
  105. ChunkInfo->Signature);
  106. if (Chunk != NULL)
  107. {
  108. //
  109. // Initialize the chunk by building the free list of entries within
  110. // it while also initializing each entry.
  111. memset(Chunk, 0, ChunkSize);
  112. FreeEntryHead = &Chunk->FreeEntryHead;
  113. InitializeListHead(FreeEntryHead);
  114. EntryPtr = (PUCHAR)Chunk + sizeof(CHUNKHEADER);
  115. EntryCount = ChunkInfo->EntriesPerChunk - 1;
  116. for (i = 0; i < EntryCount; i++)
  117. {
  118. Entry = (PENTRYHEADER)EntryPtr;
  119. Entry->Chunk = Chunk;
  120. Entry->Flags = FLAG_ENTRY_ON_FREE_LIST;
  121. InsertHeadList(FreeEntryHead,
  122. &((PENTRYHEADER)EntryPtr)->FreeEntryList);
  123. EntryPtr = EntryPtr + ChunkInfo->EntrySize;
  124. }
  125. //
  126. // EntryPtr now points to the last entry in the chunk which has not
  127. // been placed on the free list. This will be the entry returned
  128. // to the caller.
  129. Entry = (PENTRYHEADER)EntryPtr;
  130. Entry->Chunk = Chunk;
  131. Entry->RefCount = 1;
  132. Entry->Flags = ChunkInfo->InitialFlags;
  133. Entry->Signature = ChunkInfo->Signature;
  134. Chunk->EntriesInUse = 1;
  135. //
  136. // Now place the newly allocated chunk onto the list of chunks
  137. WmipEnterSMCritSection();
  138. InsertHeadList(&ChunkInfo->ChunkHead, &Chunk->ChunkList);
  139. WmipLeaveSMCritSection();
  140. } else {
  141. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Could not allocate memory for new chunk %x\n",
  142. ChunkInfo));
  143. Entry = NULL;
  144. }
  145. return(Entry);
  146. }
  147. void WmipFreeEntry(
  148. PCHUNKINFO ChunkInfo,
  149. PENTRYHEADER Entry
  150. )
  151. /*++
  152. Routine Description:
  153. This routine will free an entry within a chunk and if the chunk has no
  154. more allocated entries then the chunk will be returned to the pool.
  155. Arguments:
  156. ChunkInfo describes the chunks of structures
  157. Entry is the chunk entry to free
  158. Return Value:
  159. --*/
  160. {
  161. PCHUNKHEADER Chunk;
  162. PAGED_CODE();
  163. WmipAssert(Entry != NULL);
  164. WmipAssert(! (Entry->Flags & FLAG_ENTRY_ON_FREE_LIST));
  165. WmipAssert(Entry->Flags & FLAG_ENTRY_INVALID);
  166. WmipAssert(Entry->RefCount == 0);
  167. WmipAssert(Entry->Signature == ChunkInfo->Signature);
  168. Chunk = Entry->Chunk;
  169. WmipAssert(Chunk->EntriesInUse > 0);
  170. WmipEnterSMCritSection();
  171. if ((--Chunk->EntriesInUse == 0) &&
  172. (ChunkInfo->ChunkHead.Blink != &Chunk->ChunkList))
  173. {
  174. //
  175. // We return the chunks memory back to the heap if there are no
  176. // more entries within the chunk in use and the chunk was not the
  177. // first chunk to be allocated.
  178. RemoveEntryList(&Chunk->ChunkList);
  179. WmipLeaveSMCritSection();
  180. ExFreePoolWithTag(Chunk, ChunkInfo->Signature);
  181. } else {
  182. //
  183. // Otherwise just mark the entry as free and put it back on the
  184. // chunks free list.
  185. #if DBG
  186. memset(Entry, 0xCCCCCCCC, ChunkInfo->EntrySize);
  187. #endif
  188. Entry->Flags = FLAG_ENTRY_ON_FREE_LIST;
  189. Entry->Signature = 0;
  190. InsertTailList(&Chunk->FreeEntryHead, &Entry->FreeEntryList);
  191. WmipLeaveSMCritSection();
  192. }
  193. }
  194. ULONG WmipUnreferenceEntry(
  195. PCHUNKINFO ChunkInfo,
  196. PENTRYHEADER Entry
  197. )
  198. /*+++
  199. Routine Description:
  200. This routine will remove a reference count from the entry and if the
  201. reference count reaches zero then the entry is removed from its active
  202. list and then cleaned up and finally freed.
  203. Arguments:
  204. ChunkInfo points at structure that describes the entry
  205. Entry is the entry to unreference
  206. Return Value:
  207. New refcount of the entry
  208. ---*/
  209. {
  210. ULONG RefCount;
  211. PAGED_CODE();
  212. WmipAssert(Entry != NULL);
  213. WmipAssert(Entry->RefCount > 0);
  214. WmipAssert(Entry->Signature == ChunkInfo->Signature);
  215. WmipEnterSMCritSection();
  216. InterlockedDecrement(&Entry->RefCount);
  217. RefCount = Entry->RefCount;
  218. if (RefCount == 0)
  219. {
  220. //
  221. // Entry has reached a ref count of 0 so mark it as invalid and remove
  222. // it from its active list.
  223. Entry->Flags |= FLAG_ENTRY_INVALID;
  224. if ((Entry->InUseEntryList.Flink != NULL) &&
  225. (Entry->Flags & FLAG_ENTRY_REMOVE_LIST))
  226. {
  227. RemoveEntryList(&Entry->InUseEntryList);
  228. }
  229. WmipLeaveSMCritSection();
  230. if (ChunkInfo->EntryCleanup != NULL)
  231. {
  232. //
  233. // Call cleanup routine to free anything contained by the entry
  234. (*ChunkInfo->EntryCleanup)(ChunkInfo, Entry);
  235. }
  236. //
  237. // Place the entry back on its free list
  238. WmipFreeEntry(ChunkInfo, Entry);
  239. } else {
  240. WmipLeaveSMCritSection();
  241. }
  242. return(RefCount);
  243. }
  244. PWCHAR WmipCountedToSz(
  245. PWCHAR Counted
  246. )
  247. {
  248. PWCHAR Sz;
  249. USHORT CountedLen;
  250. PAGED_CODE();
  251. CountedLen = *Counted++;
  252. Sz = WmipAlloc(CountedLen + sizeof(WCHAR));
  253. if (Sz != NULL)
  254. {
  255. memcpy(Sz, Counted, CountedLen);
  256. Sz[CountedLen/sizeof(WCHAR)] = UNICODE_NULL;
  257. }
  258. return(Sz);
  259. }
  260. #ifdef HEAPVALIDATION
  261. PVOID WmipAllocWithTag(
  262. ULONG Size,
  263. ULONG Tag
  264. )
  265. {
  266. PVOID p;
  267. PAGED_CODE();
  268. p = ExAllocatePoolWithTag(PagedPool, Size, Tag);
  269. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAlloc %x (%x)\n", p, Size));
  270. return(p);
  271. }
  272. PVOID WmipAlloc(
  273. ULONG Size
  274. )
  275. {
  276. PVOID p;
  277. PAGED_CODE();
  278. p = ExAllocatePoolWithTag(PagedPool, Size, 'pimW');
  279. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAlloc %x (%x)\n", p, Size));
  280. return(p);
  281. }
  282. void WmipFree(
  283. PVOID p
  284. )
  285. {
  286. PAGED_CODE();
  287. WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipFree %x\n", p));
  288. WmipAssert(p != NULL);
  289. ExFreePool(p);
  290. }
  291. #endif