1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/config/cmalloc.c 5 * PURPOSE: Routines for allocating and freeing registry structures 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS *******************************************************************/ 16 17 BOOLEAN CmpAllocInited; 18 KGUARDED_MUTEX CmpAllocBucketLock; 19 LIST_ENTRY CmpFreeKCBListHead; 20 21 KGUARDED_MUTEX CmpDelayAllocBucketLock; 22 LIST_ENTRY CmpFreeDelayItemsListHead; 23 24 /* FUNCTIONS *****************************************************************/ 25 26 CODE_SEG("INIT") 27 VOID 28 NTAPI 29 CmpInitCmPrivateAlloc(VOID) 30 { 31 /* Make sure we didn't already do this */ 32 if (!CmpAllocInited) 33 { 34 /* Setup the lock and list */ 35 KeInitializeGuardedMutex(&CmpAllocBucketLock); 36 InitializeListHead(&CmpFreeKCBListHead); 37 CmpAllocInited = TRUE; 38 } 39 } 40 41 CODE_SEG("INIT") 42 VOID 43 NTAPI 44 CmpInitCmPrivateDelayAlloc(VOID) 45 { 46 /* Initialize the delay allocation list and lock */ 47 KeInitializeGuardedMutex(&CmpDelayAllocBucketLock); 48 InitializeListHead(&CmpFreeDelayItemsListHead); 49 } 50 51 VOID 52 NTAPI 53 CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb) 54 { 55 ULONG i; 56 PCM_ALLOC_PAGE AllocPage; 57 PAGED_CODE(); 58 59 /* Sanity checks */ 60 ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE); 61 for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL); 62 63 /* Check if it wasn't privately allocated */ 64 if (!Kcb->PrivateAlloc) 65 { 66 /* Free it from the pool */ 67 CmpFree(Kcb, TAG_KCB); 68 return; 69 } 70 71 /* Acquire the private allocation lock */ 72 KeAcquireGuardedMutex(&CmpAllocBucketLock); 73 74 /* Sanity check on lock ownership */ 75 CMP_ASSERT_HASH_ENTRY_LOCK(Kcb->ConvKey); 76 77 /* Add us to the free list */ 78 InsertTailList(&CmpFreeKCBListHead, &Kcb->FreeListEntry); 79 80 /* Get the allocation page */ 81 AllocPage = CmpGetAllocPageFromKcb(Kcb); 82 83 /* Sanity check */ 84 ASSERT(AllocPage->FreeCount != CM_KCBS_PER_PAGE); 85 86 /* Increase free count */ 87 if (++AllocPage->FreeCount == CM_KCBS_PER_PAGE) 88 { 89 /* Loop all the entries */ 90 for (i = 0; i < CM_KCBS_PER_PAGE; i++) 91 { 92 /* Get the KCB */ 93 Kcb = (PVOID)((ULONG_PTR)AllocPage + 94 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + 95 i * sizeof(CM_KEY_CONTROL_BLOCK)); 96 97 /* Remove the entry */ 98 RemoveEntryList(&Kcb->FreeListEntry); 99 } 100 101 /* Free the page */ 102 CmpFree(AllocPage, TAG_KCB); 103 } 104 105 /* Release the lock */ 106 KeReleaseGuardedMutex(&CmpAllocBucketLock); 107 } 108 109 PCM_KEY_CONTROL_BLOCK 110 NTAPI 111 CmpAllocateKeyControlBlock(VOID) 112 { 113 PLIST_ENTRY NextEntry; 114 PCM_KEY_CONTROL_BLOCK CurrentKcb; 115 PCM_ALLOC_PAGE AllocPage; 116 ULONG i; 117 PAGED_CODE(); 118 119 /* Check if private allocations are initialized */ 120 if (CmpAllocInited) 121 { 122 /* They are, acquire the bucket lock */ 123 KeAcquireGuardedMutex(&CmpAllocBucketLock); 124 125 /* See if there's something on the free KCB list */ 126 SearchKcbList: 127 if (!IsListEmpty(&CmpFreeKCBListHead)) 128 { 129 /* Remove the entry */ 130 NextEntry = RemoveHeadList(&CmpFreeKCBListHead); 131 132 /* Get the KCB */ 133 CurrentKcb = CONTAINING_RECORD(NextEntry, 134 CM_KEY_CONTROL_BLOCK, 135 FreeListEntry); 136 137 /* Get the allocation page */ 138 AllocPage = CmpGetAllocPageFromKcb(CurrentKcb); 139 140 /* Decrease the free count */ 141 ASSERT(AllocPage->FreeCount != 0); 142 AllocPage->FreeCount--; 143 144 /* Make sure this KCB is privately allocated */ 145 ASSERT(CurrentKcb->PrivateAlloc == 1); 146 147 /* Release the allocation lock */ 148 KeReleaseGuardedMutex(&CmpAllocBucketLock); 149 150 /* Return the KCB */ 151 return CurrentKcb; 152 } 153 154 /* Allocate an allocation page */ 155 AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_KCB); 156 if (AllocPage) 157 { 158 /* Set default entries */ 159 AllocPage->FreeCount = CM_KCBS_PER_PAGE; 160 161 /* Loop each entry */ 162 for (i = 0; i < CM_KCBS_PER_PAGE; i++) 163 { 164 /* Get this entry */ 165 CurrentKcb = (PVOID)((ULONG_PTR)AllocPage + 166 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + 167 i * sizeof(CM_KEY_CONTROL_BLOCK)); 168 169 /* Set it up */ 170 CurrentKcb->PrivateAlloc = TRUE; 171 CurrentKcb->DelayCloseEntry = NULL; 172 InsertTailList(&CmpFreeKCBListHead, 173 &CurrentKcb->FreeListEntry); 174 } 175 176 /* Now go back and search the list */ 177 goto SearchKcbList; 178 } 179 180 /* Release the allocation lock */ 181 KeReleaseGuardedMutex(&CmpAllocBucketLock); 182 } 183 184 /* Allocate a KCB only */ 185 CurrentKcb = CmpAllocate(sizeof(CM_KEY_CONTROL_BLOCK), TRUE, TAG_KCB); 186 if (CurrentKcb) 187 { 188 /* Set it up */ 189 CurrentKcb->PrivateAlloc = 0; 190 CurrentKcb->DelayCloseEntry = NULL; 191 } 192 193 /* Return it */ 194 return CurrentKcb; 195 } 196 197 PVOID 198 NTAPI 199 CmpAllocateDelayItem(VOID) 200 { 201 PCM_DELAY_ALLOC Entry; 202 PCM_ALLOC_PAGE AllocPage; 203 ULONG i; 204 PLIST_ENTRY NextEntry; 205 PAGED_CODE(); 206 207 /* Lock the allocation buckets */ 208 KeAcquireGuardedMutex(&CmpDelayAllocBucketLock); 209 210 /* Look for an item on the free list */ 211 SearchList: 212 if (!IsListEmpty(&CmpFreeDelayItemsListHead)) 213 { 214 /* Get the current entry in the list */ 215 NextEntry = RemoveHeadList(&CmpFreeDelayItemsListHead); 216 217 /* Grab the item */ 218 Entry = CONTAINING_RECORD(NextEntry, CM_DELAY_ALLOC, ListEntry); 219 220 /* Clear the list */ 221 Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL; 222 223 /* Grab the alloc page */ 224 AllocPage = CmpGetAllocPageFromDelayAlloc(Entry); 225 226 /* Decrease free entries */ 227 ASSERT(AllocPage->FreeCount != 0); 228 AllocPage->FreeCount--; 229 230 /* Release the lock */ 231 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); 232 return Entry; 233 } 234 235 /* Allocate an allocation page */ 236 AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_CM); 237 if (AllocPage) 238 { 239 /* Set default entries */ 240 AllocPage->FreeCount = CM_DELAYS_PER_PAGE; 241 242 /* Loop each entry */ 243 for (i = 0; i < CM_DELAYS_PER_PAGE; i++) 244 { 245 /* Get this entry and link it */ 246 Entry = (PVOID)((ULONG_PTR)AllocPage + 247 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + 248 i * sizeof(CM_DELAY_ALLOC)); 249 InsertTailList(&CmpFreeDelayItemsListHead, 250 &Entry->ListEntry); 251 252 /* Clear the KCB pointer */ 253 Entry->Kcb = NULL; 254 } 255 256 /* Do the search again */ 257 goto SearchList; 258 } 259 260 /* Release the lock */ 261 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); 262 return NULL; 263 } 264 265 VOID 266 NTAPI 267 CmpFreeDelayItem(PVOID Entry) 268 { 269 PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry; 270 PCM_ALLOC_PAGE AllocPage; 271 ULONG i; 272 PAGED_CODE(); 273 274 /* Lock the table */ 275 KeAcquireGuardedMutex(&CmpDelayAllocBucketLock); 276 277 /* Add the entry at the end */ 278 InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry); 279 280 /* Get the alloc page */ 281 AllocPage = CmpGetAllocPageFromDelayAlloc(Entry); 282 ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE); 283 284 /* Increase the number of free items */ 285 if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE) 286 { 287 /* Page is totally free now, loop each entry */ 288 for (i = 0; i < CM_DELAYS_PER_PAGE; i++) 289 { 290 /* Get the entry and unlink it */ 291 AllocEntry = (PVOID)((ULONG_PTR)AllocPage + 292 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + 293 i * sizeof(CM_DELAY_ALLOC)); 294 RemoveEntryList(&AllocEntry->ListEntry); 295 } 296 297 /* Now free the page */ 298 CmpFree(AllocPage, TAG_CM); 299 } 300 301 /* Release the lock */ 302 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); 303 } 304