reactos/ntoskrnl/config/cmalloc.c

303 lines
8.5 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/config/cmalloc.c
* PURPOSE: Routines for allocating and freeing registry structures
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
BOOLEAN CmpAllocInited;
KGUARDED_MUTEX CmpAllocBucketLock, CmpDelayAllocBucketLock;
LIST_ENTRY CmpFreeKCBListHead;
KGUARDED_MUTEX CmpDelayAllocBucketLock;
LIST_ENTRY CmpFreeDelayItemsListHead;
/* FUNCTIONS *****************************************************************/
VOID
NTAPI
INIT_FUNCTION
CmpInitCmPrivateAlloc(VOID)
{
/* Make sure we didn't already do this */
if (!CmpAllocInited)
{
/* Setup the lock and list */
KeInitializeGuardedMutex(&CmpAllocBucketLock);
InitializeListHead(&CmpFreeKCBListHead);
CmpAllocInited = TRUE;
}
}
VOID
NTAPI
INIT_FUNCTION
CmpInitCmPrivateDelayAlloc(VOID)
{
/* Initialize the delay allocation list and lock */
KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
InitializeListHead(&CmpFreeDelayItemsListHead);
}
VOID
NTAPI
CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
{
ULONG i;
PCM_ALLOC_PAGE AllocPage;
PAGED_CODE();
/* Sanity checks */
ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE);
for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
/* Check if it wasn't privately allocated */
if (!Kcb->PrivateAlloc)
{
/* Free it from the pool */
CmpFree(Kcb, 0);
return;
}
/* Acquire the private allocation lock */
KeAcquireGuardedMutex(&CmpAllocBucketLock);
/* Sanity check on lock ownership */
CMP_ASSERT_HASH_ENTRY_LOCK(Kcb->ConvKey);
/* Add us to the free list */
InsertTailList(&CmpFreeKCBListHead, &Kcb->FreeListEntry);
/* Get the allocation page */
AllocPage = CmpGetAllocPageFromKcb(Kcb);
/* Sanity check */
ASSERT(AllocPage->FreeCount != CM_KCBS_PER_PAGE);
/* Increase free count */
if (++AllocPage->FreeCount == CM_KCBS_PER_PAGE)
{
/* Loop all the entries */
for (i = 0; i < CM_KCBS_PER_PAGE; i++)
{
/* Get the KCB */
Kcb = (PVOID)((ULONG_PTR)AllocPage +
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
i * sizeof(CM_KEY_CONTROL_BLOCK));
/* Remove the entry */
RemoveEntryList(&Kcb->FreeListEntry);
}
/* Free the page */
CmpFree(AllocPage, 0);
}
/* Release the lock */
KeReleaseGuardedMutex(&CmpAllocBucketLock);
}
PCM_KEY_CONTROL_BLOCK
NTAPI
CmpAllocateKeyControlBlock(VOID)
{
PLIST_ENTRY NextEntry;
PCM_KEY_CONTROL_BLOCK CurrentKcb;
PCM_ALLOC_PAGE AllocPage;
ULONG i;
PAGED_CODE();
/* Check if private allocations are initialized */
if (CmpAllocInited)
{
/* They are, acquire the bucket lock */
KeAcquireGuardedMutex(&CmpAllocBucketLock);
/* See if there's something on the free KCB list */
SearchKcbList:
if (!IsListEmpty(&CmpFreeKCBListHead))
{
/* Remove the entry */
NextEntry = RemoveHeadList(&CmpFreeKCBListHead);
/* Get the KCB */
CurrentKcb = CONTAINING_RECORD(NextEntry,
CM_KEY_CONTROL_BLOCK,
FreeListEntry);
/* Get the allocation page */
AllocPage = CmpGetAllocPageFromKcb(CurrentKcb);
/* Decrease the free count */
ASSERT(AllocPage->FreeCount != 0);
AllocPage->FreeCount--;
/* Make sure this KCB is privately allocated */
ASSERT(CurrentKcb->PrivateAlloc == 1);
/* Release the allocation lock */
KeReleaseGuardedMutex(&CmpAllocBucketLock);
/* Return the KCB */
return CurrentKcb;
}
/* Allocate an allocation page */
AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_CM);
if (AllocPage)
{
/* Set default entries */
AllocPage->FreeCount = CM_KCBS_PER_PAGE;
/* Loop each entry */
for (i = 0; i < CM_KCBS_PER_PAGE; i++)
{
/* Get this entry */
CurrentKcb = (PVOID)((ULONG_PTR)AllocPage +
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
i * sizeof(CM_KEY_CONTROL_BLOCK));
/* Set it up */
CurrentKcb->PrivateAlloc = TRUE;
CurrentKcb->DelayCloseEntry = NULL;
InsertTailList(&CmpFreeKCBListHead,
&CurrentKcb->FreeListEntry);
}
/* Now go back and search the list */
goto SearchKcbList;
}
}
/* Allocate a KCB only */
CurrentKcb = CmpAllocate(sizeof(CM_KEY_CONTROL_BLOCK), TRUE, TAG_CM);
if (CurrentKcb)
{
/* Set it up */
CurrentKcb->PrivateAlloc = 0;
CurrentKcb->DelayCloseEntry = NULL;
}
/* Return it */
return CurrentKcb;
}
PVOID
NTAPI
CmpAllocateDelayItem(VOID)
{
PCM_DELAY_ALLOC Entry;
PCM_ALLOC_PAGE AllocPage;
ULONG i;
PLIST_ENTRY NextEntry;
PAGED_CODE();
/* Lock the allocation buckets */
KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
/* Look for an item on the free list */
SearchList:
if (!IsListEmpty(&CmpFreeDelayItemsListHead))
{
/* Get the current entry in the list */
NextEntry = RemoveHeadList(&CmpFreeDelayItemsListHead);
/* Grab the item */
Entry = CONTAINING_RECORD(NextEntry, CM_DELAY_ALLOC, ListEntry);
/* Clear the list */
Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL;
/* Grab the alloc page */
AllocPage = CmpGetAllocPageFromDelayAlloc(Entry);
/* Decrease free entries */
ASSERT(AllocPage->FreeCount != 0);
AllocPage->FreeCount--;
/* Release the lock */
KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
return Entry;
}
/* Allocate an allocation page */
AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_CM);
if (AllocPage)
{
/* Set default entries */
AllocPage->FreeCount = CM_DELAYS_PER_PAGE;
/* Loop each entry */
for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
{
/* Get this entry and link it */
Entry = (PVOID)((ULONG_PTR)AllocPage +
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
i * sizeof(CM_DELAY_ALLOC));
InsertTailList(&CmpFreeDelayItemsListHead,
&Entry->ListEntry);
/* Clear the KCB pointer */
Entry->Kcb = NULL;
}
}
else
{
/* Release the lock */
KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
return NULL;
}
/* Do the search again */
goto SearchList;
}
VOID
NTAPI
CmpFreeDelayItem(PVOID Entry)
{
PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry;
PCM_ALLOC_PAGE AllocPage;
ULONG i;
PAGED_CODE();
/* Lock the table */
KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
/* Add the entry at the end */
InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry);
/* Get the alloc page */
AllocPage = CmpGetAllocPageFromDelayAlloc(Entry);
ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE);
/* Increase the number of free items */
if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE)
{
/* Page is totally free now, loop each entry */
for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
{
/* Get the entry and unlink it */
AllocEntry = (PVOID)((ULONG_PTR)AllocPage +
FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
i * sizeof(CM_DELAY_ALLOC));
RemoveEntryList(&AllocEntry->ListEntry);
}
/* Now free the page */
CmpFree(AllocPage, 0);
}
/* Release the lock */
KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
}