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.

366 lines
7.0 KiB

  1. /*++
  2. Copyright (c) 20001 Microsoft Corporation
  3. Module Name:
  4. cmalloc.c
  5. Abstract:
  6. Provides routines for implementing the registry's own pool allocator.
  7. Author:
  8. Dragos C. Sambotin (DragosS) 07-Feb-2001
  9. Revision History:
  10. --*/
  11. #include "cmp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(INIT,CmpInitCmPrivateAlloc)
  14. #pragma alloc_text(PAGE,CmpDestroyCmPrivateAlloc)
  15. #pragma alloc_text(PAGE,CmpAllocateKeyControlBlock)
  16. #pragma alloc_text(PAGE,CmpFreeKeyControlBlock)
  17. #endif
  18. typedef struct _CM_ALLOC_PAGE {
  19. ULONG FreeCount; // number of free kcbs
  20. ULONG Reserved; // alignment
  21. #if DBG
  22. LIST_ENTRY CmPageListEntry;// debug only to track pages we are using
  23. #endif
  24. PVOID AllocPage; // crud allocations - this member is NOT USED
  25. } CM_ALLOC_PAGE, *PCM_ALLOC_PAGE;
  26. #define CM_KCB_ENTRY_SIZE sizeof( CM_KEY_CONTROL_BLOCK )
  27. #define CM_ALLOC_PAGES (PAGE_SIZE / sizeof(CM_ALLOC_ENTRY))
  28. #define CM_KCBS_PER_PAGE ((PAGE_SIZE - FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage)) / CM_KCB_ENTRY_SIZE)
  29. #define KCB_TO_PAGE_ADDRESS( kcb ) (PVOID)(((ULONG_PTR)(kcb)) & ~(PAGE_SIZE - 1))
  30. #define KCB_TO_ALLOC_PAGE( kcb ) ((PCM_ALLOC_PAGE)KCB_TO_PAGE_ADDRESS(kcb))
  31. LIST_ENTRY CmpFreeKCBListHead; // list of free kcbs
  32. BOOLEAN CmpAllocInited = FALSE;
  33. #if DBG
  34. ULONG CmpTotalKcbUsed = 0;
  35. ULONG CmpTotalKcbFree = 0;
  36. LIST_ENTRY CmPageListHead;
  37. #endif
  38. FAST_MUTEX CmpAllocBucketLock; // used to protect the bucket
  39. #define LOCK_ALLOC_BUCKET() ExAcquireFastMutexUnsafe(&CmpAllocBucketLock)
  40. #define UNLOCK_ALLOC_BUCKET() ExReleaseFastMutexUnsafe(&CmpAllocBucketLock)
  41. VOID
  42. CmpInitCmPrivateAlloc( )
  43. /*++
  44. Routine Description:
  45. Initialize the CmPrivate pool allocation module
  46. Arguments:
  47. Return Value:
  48. --*/
  49. {
  50. if( CmpAllocInited ) {
  51. //
  52. // already inited
  53. //
  54. return;
  55. }
  56. #if DBG
  57. InitializeListHead(&(CmPageListHead));
  58. #endif //DBG
  59. InitializeListHead(&(CmpFreeKCBListHead));
  60. //
  61. // init the bucket lock
  62. //
  63. ExInitializeFastMutex(&CmpAllocBucketLock);
  64. CmpAllocInited = TRUE;
  65. }
  66. VOID
  67. CmpDestroyCmPrivateAlloc( )
  68. /*++
  69. Routine Description:
  70. Frees memory used byt the CmPrivate pool allocation module
  71. Arguments:
  72. Return Value:
  73. --*/
  74. {
  75. PAGED_CODE();
  76. if( !CmpAllocInited ) {
  77. return;
  78. }
  79. #if DBG
  80. //
  81. // sanity
  82. //
  83. ASSERT( CmpTotalKcbUsed == 0 );
  84. ASSERT( CmpTotalKcbUsed == 0 );
  85. ASSERT( IsListEmpty(&(CmPageListHead)) == TRUE );
  86. #endif
  87. }
  88. PCM_KEY_CONTROL_BLOCK
  89. CmpAllocateKeyControlBlock( )
  90. /*++
  91. Routine Description:
  92. Allocates a kcb; first try from our own allocator.
  93. If it doesn't work (we have maxed out our number of allocs
  94. or private allocator is not inited)
  95. try from paged pool
  96. Arguments:
  97. Return Value:
  98. The new kcb
  99. --*/
  100. {
  101. USHORT j;
  102. PCM_KEY_CONTROL_BLOCK kcb = NULL;
  103. PVOID Page;
  104. PCM_ALLOC_PAGE AllocPage;
  105. PAGED_CODE();
  106. if( !CmpAllocInited ) {
  107. //
  108. // not inited
  109. //
  110. goto AllocFromPool;
  111. }
  112. LOCK_ALLOC_BUCKET();
  113. SearchFreeKcb:
  114. //
  115. // try to find a free one
  116. //
  117. if( IsListEmpty(&CmpFreeKCBListHead) == FALSE ) {
  118. //
  119. // found one
  120. //
  121. kcb = (PCM_KEY_CONTROL_BLOCK)RemoveHeadList(&CmpFreeKCBListHead);
  122. kcb = CONTAINING_RECORD(kcb,
  123. CM_KEY_CONTROL_BLOCK,
  124. FreeListEntry);
  125. AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
  126. ASSERT( AllocPage->FreeCount != 0 );
  127. AllocPage->FreeCount--;
  128. //
  129. // set when page was allocated
  130. //
  131. ASSERT( kcb->PrivateAlloc == 1);
  132. #if DBG
  133. CmpTotalKcbUsed++;
  134. CmpTotalKcbFree--;
  135. #endif //DBG
  136. UNLOCK_ALLOC_BUCKET();
  137. return kcb;
  138. }
  139. ASSERT( IsListEmpty(&CmpFreeKCBListHead) == TRUE );
  140. ASSERT( CmpTotalKcbFree == 0 );
  141. //
  142. // we need to allocate a new page as we ran out of free kcbs
  143. //
  144. //
  145. // allocate a new page and insert all kcbs in the freelist
  146. //
  147. AllocPage = (PCM_ALLOC_PAGE)ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, CM_ALLOCATE_TAG|PROTECTED_POOL);
  148. if( AllocPage == NULL ) {
  149. //
  150. // we might be low on pool; maybe small pool chunks will work
  151. //
  152. UNLOCK_ALLOC_BUCKET();
  153. goto AllocFromPool;
  154. }
  155. //
  156. // set up the page
  157. //
  158. AllocPage->FreeCount = CM_KCBS_PER_PAGE;
  159. #if DBG
  160. AllocPage->Reserved = 0;
  161. InsertTailList(
  162. &CmPageListHead,
  163. &(AllocPage->CmPageListEntry)
  164. );
  165. #endif //DBG
  166. //
  167. // now the dirty job; insert all kcbs inside the page in the free list
  168. //
  169. for(j=0;j<CM_KCBS_PER_PAGE;j++) {
  170. kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
  171. //
  172. // set it here; only once
  173. //
  174. kcb->PrivateAlloc = 1;
  175. InsertTailList(
  176. &CmpFreeKCBListHead,
  177. &(kcb->FreeListEntry)
  178. );
  179. }
  180. #if DBG
  181. CmpTotalKcbFree += CM_KCBS_PER_PAGE;
  182. #endif //DBG
  183. //
  184. // this time will find one for sure
  185. //
  186. goto SearchFreeKcb;
  187. AllocFromPool:
  188. kcb = ExAllocatePoolWithTag(PagedPool,
  189. sizeof(CM_KEY_CONTROL_BLOCK),
  190. CM_KCB_TAG | PROTECTED_POOL);
  191. if( kcb != NULL ) {
  192. //
  193. // clear the private alloc flag
  194. //
  195. kcb->PrivateAlloc = 0;
  196. }
  197. return kcb;
  198. }
  199. VOID
  200. CmpFreeKeyControlBlock( PCM_KEY_CONTROL_BLOCK kcb )
  201. /*++
  202. Routine Description:
  203. Frees a kcb; if it's allocated from our own pool put it back in the free list.
  204. If it's allocated from general pool, just free it.
  205. Arguments:
  206. kcb to free
  207. Return Value:
  208. --*/
  209. {
  210. USHORT j;
  211. PCM_ALLOC_PAGE AllocPage;
  212. PAGED_CODE();
  213. ASSERT_KEYBODY_LIST_EMPTY(kcb);
  214. if( !kcb->PrivateAlloc ) {
  215. //
  216. // just free it and be done with it
  217. //
  218. ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
  219. return;
  220. }
  221. LOCK_ALLOC_BUCKET();
  222. #if DBG
  223. CmpTotalKcbFree ++;
  224. CmpTotalKcbUsed --;
  225. #endif
  226. //
  227. // add kcb to freelist
  228. //
  229. InsertTailList(
  230. &CmpFreeKCBListHead,
  231. &(kcb->FreeListEntry)
  232. );
  233. //
  234. // get the page
  235. //
  236. AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
  237. //
  238. // not all are free
  239. //
  240. ASSERT( AllocPage->FreeCount != CM_KCBS_PER_PAGE);
  241. AllocPage->FreeCount++;
  242. if( AllocPage->FreeCount == CM_KCBS_PER_PAGE ) {
  243. //
  244. // entire page is free; let it go
  245. //
  246. //
  247. // first; iterate through the free kcb list and remove all kcbs inside this page
  248. //
  249. for(j=0;j<CM_KCBS_PER_PAGE;j++) {
  250. kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
  251. RemoveEntryList(&(kcb->FreeListEntry));
  252. }
  253. #if DBG
  254. CmpTotalKcbFree -= CM_KCBS_PER_PAGE;
  255. RemoveEntryList(&(AllocPage->CmPageListEntry));
  256. #endif
  257. ExFreePoolWithTag(AllocPage, CM_ALLOCATE_TAG|PROTECTED_POOL);
  258. }
  259. UNLOCK_ALLOC_BUCKET();
  260. }