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, CmpDelayAllocBucketLock; 19 20 LIST_ENTRY CmpFreeKCBListHead; 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 181 /* Allocate a KCB only */ 182 CurrentKcb = CmpAllocate(sizeof(CM_KEY_CONTROL_BLOCK), TRUE, TAG_KCB); 183 if (CurrentKcb) 184 { 185 /* Set it up */ 186 CurrentKcb->PrivateAlloc = 0; 187 CurrentKcb->DelayCloseEntry = NULL; 188 } 189 190 /* Return it */ 191 return CurrentKcb; 192 } 193 194 PVOID 195 NTAPI 196 CmpAllocateDelayItem(VOID) 197 { 198 PCM_DELAY_ALLOC Entry; 199 PCM_ALLOC_PAGE AllocPage; 200 ULONG i; 201 PLIST_ENTRY NextEntry; 202 PAGED_CODE(); 203 204 /* Lock the allocation buckets */ 205 KeAcquireGuardedMutex(&CmpDelayAllocBucketLock); 206 207 /* Look for an item on the free list */ 208 SearchList: 209 if (!IsListEmpty(&CmpFreeDelayItemsListHead)) 210 { 211 /* Get the current entry in the list */ 212 NextEntry = RemoveHeadList(&CmpFreeDelayItemsListHead); 213 214 /* Grab the item */ 215 Entry = CONTAINING_RECORD(NextEntry, CM_DELAY_ALLOC, ListEntry); 216 217 /* Clear the list */ 218 Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL; 219 220 /* Grab the alloc page */ 221 AllocPage = CmpGetAllocPageFromDelayAlloc(Entry); 222 223 /* Decrease free entries */ 224 ASSERT(AllocPage->FreeCount != 0); 225 AllocPage->FreeCount--; 226 227 /* Release the lock */ 228 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); 229 return Entry; 230 } 231 232 /* Allocate an allocation page */ 233 AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_CM); 234 if (AllocPage) 235 { 236 /* Set default entries */ 237 AllocPage->FreeCount = CM_DELAYS_PER_PAGE; 238 239 /* Loop each entry */ 240 for (i = 0; i < CM_DELAYS_PER_PAGE; i++) 241 { 242 /* Get this entry and link it */ 243 Entry = (PVOID)((ULONG_PTR)AllocPage + 244 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + 245 i * sizeof(CM_DELAY_ALLOC)); 246 InsertTailList(&CmpFreeDelayItemsListHead, 247 &Entry->ListEntry); 248 249 /* Clear the KCB pointer */ 250 Entry->Kcb = NULL; 251 } 252 } 253 else 254 { 255 /* Release the lock */ 256 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); 257 return NULL; 258 } 259 260 /* Do the search again */ 261 goto SearchList; 262 } 263 264 VOID 265 NTAPI 266 CmpFreeDelayItem(PVOID Entry) 267 { 268 PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry; 269 PCM_ALLOC_PAGE AllocPage; 270 ULONG i; 271 PAGED_CODE(); 272 273 /* Lock the table */ 274 KeAcquireGuardedMutex(&CmpDelayAllocBucketLock); 275 276 /* Add the entry at the end */ 277 InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry); 278 279 /* Get the alloc page */ 280 AllocPage = CmpGetAllocPageFromDelayAlloc(Entry); 281 ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE); 282 283 /* Increase the number of free items */ 284 if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE) 285 { 286 /* Page is totally free now, loop each entry */ 287 for (i = 0; i < CM_DELAYS_PER_PAGE; i++) 288 { 289 /* Get the entry and unlink it */ 290 AllocEntry = (PVOID)((ULONG_PTR)AllocPage + 291 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) + 292 i * sizeof(CM_DELAY_ALLOC)); 293 RemoveEntryList(&AllocEntry->ListEntry); 294 } 295 296 /* Now free the page */ 297 CmpFree(AllocPage, TAG_CM); 298 } 299 300 /* Release the lock */ 301 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock); 302 } 303