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.

365 lines
7.4 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. PCM_ALLOC_PAGE AllocPage;
  104. PAGED_CODE();
  105. if( !CmpAllocInited ) {
  106. //
  107. // not inited
  108. //
  109. goto AllocFromPool;
  110. }
  111. LOCK_ALLOC_BUCKET();
  112. SearchFreeKcb:
  113. //
  114. // try to find a free one
  115. //
  116. if( IsListEmpty(&CmpFreeKCBListHead) == FALSE ) {
  117. //
  118. // found one
  119. //
  120. kcb = (PCM_KEY_CONTROL_BLOCK)RemoveHeadList(&CmpFreeKCBListHead);
  121. kcb = CONTAINING_RECORD(kcb,
  122. CM_KEY_CONTROL_BLOCK,
  123. FreeListEntry);
  124. AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
  125. ASSERT( AllocPage->FreeCount != 0 );
  126. AllocPage->FreeCount--;
  127. //
  128. // set when page was allocated
  129. //
  130. ASSERT( kcb->PrivateAlloc == 1);
  131. #if DBG
  132. CmpTotalKcbUsed++;
  133. CmpTotalKcbFree--;
  134. #endif //DBG
  135. UNLOCK_ALLOC_BUCKET();
  136. return kcb;
  137. }
  138. ASSERT( IsListEmpty(&CmpFreeKCBListHead) == TRUE );
  139. ASSERT( CmpTotalKcbFree == 0 );
  140. //
  141. // we need to allocate a new page as we ran out of free kcbs
  142. //
  143. //
  144. // allocate a new page and insert all kcbs in the freelist
  145. //
  146. AllocPage = (PCM_ALLOC_PAGE)ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, CM_ALLOCATE_TAG|PROTECTED_POOL);
  147. if( AllocPage == NULL ) {
  148. //
  149. // we might be low on pool; maybe small pool chunks will work
  150. //
  151. UNLOCK_ALLOC_BUCKET();
  152. goto AllocFromPool;
  153. }
  154. //
  155. // set up the page
  156. //
  157. AllocPage->FreeCount = CM_KCBS_PER_PAGE;
  158. #if DBG
  159. AllocPage->Reserved = 0;
  160. InsertTailList(
  161. &CmPageListHead,
  162. &(AllocPage->CmPageListEntry)
  163. );
  164. #endif //DBG
  165. //
  166. // now the dirty job; insert all kcbs inside the page in the free list
  167. //
  168. for(j=0;j<CM_KCBS_PER_PAGE;j++) {
  169. kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
  170. //
  171. // set it here; only once
  172. //
  173. kcb->PrivateAlloc = 1;
  174. InsertTailList(
  175. &CmpFreeKCBListHead,
  176. &(kcb->FreeListEntry)
  177. );
  178. }
  179. #if DBG
  180. CmpTotalKcbFree += CM_KCBS_PER_PAGE;
  181. #endif //DBG
  182. //
  183. // this time will find one for sure
  184. //
  185. goto SearchFreeKcb;
  186. AllocFromPool:
  187. kcb = ExAllocatePoolWithTag(PagedPool,
  188. sizeof(CM_KEY_CONTROL_BLOCK),
  189. CM_KCB_TAG | PROTECTED_POOL);
  190. if( kcb != NULL ) {
  191. //
  192. // clear the private alloc flag
  193. //
  194. kcb->PrivateAlloc = 0;
  195. }
  196. return kcb;
  197. }
  198. VOID
  199. CmpFreeKeyControlBlock( PCM_KEY_CONTROL_BLOCK kcb )
  200. /*++
  201. Routine Description:
  202. Frees a kcb; if it's allocated from our own pool put it back in the free list.
  203. If it's allocated from general pool, just free it.
  204. Arguments:
  205. kcb to free
  206. Return Value:
  207. --*/
  208. {
  209. USHORT j;
  210. PCM_ALLOC_PAGE AllocPage;
  211. PAGED_CODE();
  212. ASSERT_KEYBODY_LIST_EMPTY(kcb);
  213. if( !kcb->PrivateAlloc ) {
  214. //
  215. // just free it and be done with it
  216. //
  217. ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
  218. return;
  219. }
  220. LOCK_ALLOC_BUCKET();
  221. #if DBG
  222. CmpTotalKcbFree ++;
  223. CmpTotalKcbUsed --;
  224. #endif
  225. //
  226. // add kcb to freelist
  227. //
  228. InsertTailList(
  229. &CmpFreeKCBListHead,
  230. &(kcb->FreeListEntry)
  231. );
  232. //
  233. // get the page
  234. //
  235. AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
  236. //
  237. // not all are free
  238. //
  239. ASSERT( AllocPage->FreeCount != CM_KCBS_PER_PAGE);
  240. AllocPage->FreeCount++;
  241. if( AllocPage->FreeCount == CM_KCBS_PER_PAGE ) {
  242. //
  243. // entire page is free; let it go
  244. //
  245. //
  246. // first; iterate through the free kcb list and remove all kcbs inside this page
  247. //
  248. for(j=0;j<CM_KCBS_PER_PAGE;j++) {
  249. kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
  250. RemoveEntryList(&(kcb->FreeListEntry));
  251. }
  252. #if DBG
  253. CmpTotalKcbFree -= CM_KCBS_PER_PAGE;
  254. RemoveEntryList(&(AllocPage->CmPageListEntry));
  255. #endif
  256. ExFreePoolWithTag(AllocPage, CM_ALLOCATE_TAG|PROTECTED_POOL);
  257. }
  258. UNLOCK_ALLOC_BUCKET();
  259. }