367 lines
7 KiB
C
367 lines
7 KiB
C
/*++
|
|
|
|
Copyright (c) 20001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cmalloc.c
|
|
|
|
Abstract:
|
|
|
|
Provides routines for implementing the registry's own pool allocator.
|
|
|
|
Author:
|
|
|
|
Dragos C. Sambotin (DragosS) 07-Feb-2001
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "cmp.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,CmpInitCmPrivateAlloc)
|
|
#pragma alloc_text(PAGE,CmpDestroyCmPrivateAlloc)
|
|
#pragma alloc_text(PAGE,CmpAllocateKeyControlBlock)
|
|
#pragma alloc_text(PAGE,CmpFreeKeyControlBlock)
|
|
#endif
|
|
|
|
typedef struct _CM_ALLOC_PAGE {
|
|
ULONG FreeCount; // number of free kcbs
|
|
ULONG Reserved; // alignment
|
|
#if DBG
|
|
LIST_ENTRY CmPageListEntry;// debug only to track pages we are using
|
|
#endif
|
|
PVOID AllocPage; // crud allocations - this member is NOT USED
|
|
} CM_ALLOC_PAGE, *PCM_ALLOC_PAGE;
|
|
|
|
#define CM_KCB_ENTRY_SIZE sizeof( CM_KEY_CONTROL_BLOCK )
|
|
#define CM_ALLOC_PAGES (PAGE_SIZE / sizeof(CM_ALLOC_ENTRY))
|
|
#define CM_KCBS_PER_PAGE ((PAGE_SIZE - FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage)) / CM_KCB_ENTRY_SIZE)
|
|
|
|
#define KCB_TO_PAGE_ADDRESS( kcb ) (PVOID)(((ULONG_PTR)(kcb)) & ~(PAGE_SIZE - 1))
|
|
#define KCB_TO_ALLOC_PAGE( kcb ) ((PCM_ALLOC_PAGE)KCB_TO_PAGE_ADDRESS(kcb))
|
|
|
|
LIST_ENTRY CmpFreeKCBListHead; // list of free kcbs
|
|
BOOLEAN CmpAllocInited = FALSE;
|
|
|
|
#if DBG
|
|
ULONG CmpTotalKcbUsed = 0;
|
|
ULONG CmpTotalKcbFree = 0;
|
|
LIST_ENTRY CmPageListHead;
|
|
#endif
|
|
|
|
FAST_MUTEX CmpAllocBucketLock; // used to protect the bucket
|
|
|
|
#define LOCK_ALLOC_BUCKET() ExAcquireFastMutexUnsafe(&CmpAllocBucketLock)
|
|
#define UNLOCK_ALLOC_BUCKET() ExReleaseFastMutexUnsafe(&CmpAllocBucketLock)
|
|
|
|
VOID
|
|
CmpInitCmPrivateAlloc( )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the CmPrivate pool allocation module
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
if( CmpAllocInited ) {
|
|
//
|
|
// already inited
|
|
//
|
|
return;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
InitializeListHead(&(CmPageListHead));
|
|
#endif //DBG
|
|
|
|
InitializeListHead(&(CmpFreeKCBListHead));
|
|
|
|
//
|
|
// init the bucket lock
|
|
//
|
|
ExInitializeFastMutex(&CmpAllocBucketLock);
|
|
|
|
CmpAllocInited = TRUE;
|
|
}
|
|
|
|
VOID
|
|
CmpDestroyCmPrivateAlloc( )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees memory used byt the CmPrivate pool allocation module
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if( !CmpAllocInited ) {
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
//
|
|
// sanity
|
|
//
|
|
ASSERT( CmpTotalKcbUsed == 0 );
|
|
ASSERT( CmpTotalKcbUsed == 0 );
|
|
ASSERT( IsListEmpty(&(CmPageListHead)) == TRUE );
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
PCM_KEY_CONTROL_BLOCK
|
|
CmpAllocateKeyControlBlock( )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocates a kcb; first try from our own allocator.
|
|
If it doesn't work (we have maxed out our number of allocs
|
|
or private allocator is not inited)
|
|
try from paged pool
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
The new kcb
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT j;
|
|
PCM_KEY_CONTROL_BLOCK kcb = NULL;
|
|
PVOID Page;
|
|
PCM_ALLOC_PAGE AllocPage;
|
|
|
|
PAGED_CODE();
|
|
|
|
if( !CmpAllocInited ) {
|
|
//
|
|
// not inited
|
|
//
|
|
goto AllocFromPool;
|
|
}
|
|
|
|
LOCK_ALLOC_BUCKET();
|
|
|
|
SearchFreeKcb:
|
|
//
|
|
// try to find a free one
|
|
//
|
|
if( IsListEmpty(&CmpFreeKCBListHead) == FALSE ) {
|
|
//
|
|
// found one
|
|
//
|
|
kcb = (PCM_KEY_CONTROL_BLOCK)RemoveHeadList(&CmpFreeKCBListHead);
|
|
kcb = CONTAINING_RECORD(kcb,
|
|
CM_KEY_CONTROL_BLOCK,
|
|
FreeListEntry);
|
|
|
|
AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
|
|
|
|
ASSERT( AllocPage->FreeCount != 0 );
|
|
|
|
AllocPage->FreeCount--;
|
|
|
|
//
|
|
// set when page was allocated
|
|
//
|
|
ASSERT( kcb->PrivateAlloc == 1);
|
|
|
|
#if DBG
|
|
CmpTotalKcbUsed++;
|
|
CmpTotalKcbFree--;
|
|
#endif //DBG
|
|
|
|
UNLOCK_ALLOC_BUCKET();
|
|
return kcb;
|
|
}
|
|
|
|
ASSERT( IsListEmpty(&CmpFreeKCBListHead) == TRUE );
|
|
ASSERT( CmpTotalKcbFree == 0 );
|
|
|
|
//
|
|
// we need to allocate a new page as we ran out of free kcbs
|
|
//
|
|
|
|
//
|
|
// allocate a new page and insert all kcbs in the freelist
|
|
//
|
|
AllocPage = (PCM_ALLOC_PAGE)ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, CM_ALLOCATE_TAG|PROTECTED_POOL);
|
|
if( AllocPage == NULL ) {
|
|
//
|
|
// we might be low on pool; maybe small pool chunks will work
|
|
//
|
|
UNLOCK_ALLOC_BUCKET();
|
|
goto AllocFromPool;
|
|
}
|
|
|
|
//
|
|
// set up the page
|
|
//
|
|
AllocPage->FreeCount = CM_KCBS_PER_PAGE;
|
|
|
|
#if DBG
|
|
AllocPage->Reserved = 0;
|
|
InsertTailList(
|
|
&CmPageListHead,
|
|
&(AllocPage->CmPageListEntry)
|
|
);
|
|
#endif //DBG
|
|
|
|
|
|
//
|
|
// now the dirty job; insert all kcbs inside the page in the free list
|
|
//
|
|
for(j=0;j<CM_KCBS_PER_PAGE;j++) {
|
|
kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
|
|
|
|
//
|
|
// set it here; only once
|
|
//
|
|
kcb->PrivateAlloc = 1;
|
|
|
|
InsertTailList(
|
|
&CmpFreeKCBListHead,
|
|
&(kcb->FreeListEntry)
|
|
);
|
|
}
|
|
|
|
#if DBG
|
|
CmpTotalKcbFree += CM_KCBS_PER_PAGE;
|
|
#endif //DBG
|
|
|
|
//
|
|
// this time will find one for sure
|
|
//
|
|
goto SearchFreeKcb;
|
|
|
|
AllocFromPool:
|
|
kcb = ExAllocatePoolWithTag(PagedPool,
|
|
sizeof(CM_KEY_CONTROL_BLOCK),
|
|
CM_KCB_TAG | PROTECTED_POOL);
|
|
|
|
if( kcb != NULL ) {
|
|
//
|
|
// clear the private alloc flag
|
|
//
|
|
kcb->PrivateAlloc = 0;
|
|
}
|
|
|
|
return kcb;
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpFreeKeyControlBlock( PCM_KEY_CONTROL_BLOCK kcb )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Frees a kcb; if it's allocated from our own pool put it back in the free list.
|
|
If it's allocated from general pool, just free it.
|
|
|
|
Arguments:
|
|
|
|
kcb to free
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
USHORT j;
|
|
PCM_ALLOC_PAGE AllocPage;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT_KEYBODY_LIST_EMPTY(kcb);
|
|
|
|
if( !kcb->PrivateAlloc ) {
|
|
//
|
|
// just free it and be done with it
|
|
//
|
|
ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL);
|
|
return;
|
|
}
|
|
|
|
LOCK_ALLOC_BUCKET();
|
|
|
|
#if DBG
|
|
CmpTotalKcbFree ++;
|
|
CmpTotalKcbUsed --;
|
|
#endif
|
|
|
|
//
|
|
// add kcb to freelist
|
|
//
|
|
InsertTailList(
|
|
&CmpFreeKCBListHead,
|
|
&(kcb->FreeListEntry)
|
|
);
|
|
|
|
//
|
|
// get the page
|
|
//
|
|
AllocPage = (PCM_ALLOC_PAGE)KCB_TO_ALLOC_PAGE( kcb );
|
|
|
|
//
|
|
// not all are free
|
|
//
|
|
ASSERT( AllocPage->FreeCount != CM_KCBS_PER_PAGE);
|
|
|
|
AllocPage->FreeCount++;
|
|
|
|
if( AllocPage->FreeCount == CM_KCBS_PER_PAGE ) {
|
|
//
|
|
// entire page is free; let it go
|
|
//
|
|
//
|
|
// first; iterate through the free kcb list and remove all kcbs inside this page
|
|
//
|
|
for(j=0;j<CM_KCBS_PER_PAGE;j++) {
|
|
kcb = (PCM_KEY_CONTROL_BLOCK)((PUCHAR)AllocPage + FIELD_OFFSET(CM_ALLOC_PAGE,AllocPage) + j*CM_KCB_ENTRY_SIZE);
|
|
|
|
RemoveEntryList(&(kcb->FreeListEntry));
|
|
}
|
|
#if DBG
|
|
CmpTotalKcbFree -= CM_KCBS_PER_PAGE;
|
|
RemoveEntryList(&(AllocPage->CmPageListEntry));
|
|
#endif
|
|
ExFreePoolWithTag(AllocPage, CM_ALLOCATE_TAG|PROTECTED_POOL);
|
|
}
|
|
|
|
UNLOCK_ALLOC_BUCKET();
|
|
|
|
}
|
|
|
|
|