|
|
/*++
Copyright (c) 1995-1999 Microsoft Corporation
Module Name:
chunk.c
Abstract: This routine will manage allocations of chunks of structures
Author:
16-Jan-1997 AlanWar
Revision History:
--*/
#include "wmikmp.h"
PENTRYHEADER WmipAllocEntry( PCHUNKINFO ChunkInfo );
void WmipFreeEntry( PCHUNKINFO ChunkInfo, PENTRYHEADER Entry );
ULONG WmipUnreferenceEntry( PCHUNKINFO ChunkInfo, PENTRYHEADER Entry );
PWCHAR WmipCountedToSz( PWCHAR Counted );
#if HEAPVALIDATION
PVOID WmipAlloc( ULONG Size );
void WmipFree( PVOID p ); #endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,WmipAllocEntry)
#pragma alloc_text(PAGE,WmipFreeEntry)
#pragma alloc_text(PAGE,WmipUnreferenceEntry)
#pragma alloc_text(PAGE,WmipCountedToSz)
#if HEAPVALIDATION
#pragma alloc_text(PAGE,WmipAllocWithTag)
#pragma alloc_text(PAGE,WmipAlloc)
#pragma alloc_text(PAGE,WmipFree)
#endif
#endif
//
// TODO: Use Ex lookaside lists instead of my own allocations
//
PENTRYHEADER WmipAllocEntry( PCHUNKINFO ChunkInfo ) /*++
Routine Description:
This routine will allocate a single structure within a list of chunks of structures.
Arguments:
ChunkInfo describes the chunks of structures
Return Value:
Pointer to structure or NULL if one cannot be allocated. Entry returns with its refcount set to 1
--*/ { PLIST_ENTRY ChunkList, EntryList, FreeEntryHead; PCHUNKHEADER Chunk; PUCHAR EntryPtr; ULONG EntryCount, ChunkSize; PENTRYHEADER Entry; ULONG i;
PAGED_CODE(); WmipEnterSMCritSection(); ChunkList = ChunkInfo->ChunkHead.Flink;
//
// Loop over all chunks to see if any chunk has a free entry for us
while(ChunkList != &ChunkInfo->ChunkHead) { Chunk = CONTAINING_RECORD(ChunkList, CHUNKHEADER, ChunkList); if (! IsListEmpty(&Chunk->FreeEntryHead)) { EntryList = RemoveHeadList(&Chunk->FreeEntryHead); Chunk->EntriesInUse++; WmipLeaveSMCritSection(); Entry = (CONTAINING_RECORD(EntryList, ENTRYHEADER, FreeEntryList)); WmipAssert(Entry->Flags & FLAG_ENTRY_ON_FREE_LIST); memset(Entry, 0, ChunkInfo->EntrySize); Entry->Chunk = Chunk; Entry->RefCount = 1; Entry->Flags = ChunkInfo->InitialFlags; Entry->Signature = ChunkInfo->Signature; #if DBG
InterlockedIncrement(&ChunkInfo->AllocCount); #endif
return(Entry); } ChunkList = ChunkList->Flink; } WmipLeaveSMCritSection();
//
// There are no more free entries in any of the chunks. Allocate a new
// chunk if we can
ChunkSize = (ChunkInfo->EntrySize * ChunkInfo->EntriesPerChunk) + sizeof(CHUNKHEADER); Chunk = (PCHUNKHEADER)ExAllocatePoolWithTag(PagedPool, ChunkSize, ChunkInfo->Signature); if (Chunk != NULL) { //
// Initialize the chunk by building the free list of entries within
// it while also initializing each entry.
memset(Chunk, 0, ChunkSize);
FreeEntryHead = &Chunk->FreeEntryHead; InitializeListHead(FreeEntryHead);
EntryPtr = (PUCHAR)Chunk + sizeof(CHUNKHEADER); EntryCount = ChunkInfo->EntriesPerChunk - 1;
for (i = 0; i < EntryCount; i++) { Entry = (PENTRYHEADER)EntryPtr; Entry->Chunk = Chunk; Entry->Flags = FLAG_ENTRY_ON_FREE_LIST; InsertHeadList(FreeEntryHead, &((PENTRYHEADER)EntryPtr)->FreeEntryList); EntryPtr = EntryPtr + ChunkInfo->EntrySize; } //
// EntryPtr now points to the last entry in the chunk which has not
// been placed on the free list. This will be the entry returned
// to the caller.
Entry = (PENTRYHEADER)EntryPtr; Entry->Chunk = Chunk; Entry->RefCount = 1; Entry->Flags = ChunkInfo->InitialFlags; Entry->Signature = ChunkInfo->Signature;
Chunk->EntriesInUse = 1;
//
// Now place the newly allocated chunk onto the list of chunks
WmipEnterSMCritSection(); InsertHeadList(&ChunkInfo->ChunkHead, &Chunk->ChunkList); WmipLeaveSMCritSection();
} else { WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Could not allocate memory for new chunk %x\n", ChunkInfo)); Entry = NULL; } return(Entry); }
void WmipFreeEntry( PCHUNKINFO ChunkInfo, PENTRYHEADER Entry ) /*++
Routine Description:
This routine will free an entry within a chunk and if the chunk has no more allocated entries then the chunk will be returned to the pool.
Arguments:
ChunkInfo describes the chunks of structures
Entry is the chunk entry to free
Return Value:
--*/ { PCHUNKHEADER Chunk;
PAGED_CODE(); WmipAssert(Entry != NULL); WmipAssert(! (Entry->Flags & FLAG_ENTRY_ON_FREE_LIST)); WmipAssert(Entry->Flags & FLAG_ENTRY_INVALID); WmipAssert(Entry->RefCount == 0); WmipAssert(Entry->Signature == ChunkInfo->Signature);
Chunk = Entry->Chunk; WmipAssert(Chunk->EntriesInUse > 0);
WmipEnterSMCritSection(); if ((--Chunk->EntriesInUse == 0) && (ChunkInfo->ChunkHead.Blink != &Chunk->ChunkList)) { //
// We return the chunks memory back to the heap if there are no
// more entries within the chunk in use and the chunk was not the
// first chunk to be allocated.
RemoveEntryList(&Chunk->ChunkList); WmipLeaveSMCritSection(); ExFreePoolWithTag(Chunk, ChunkInfo->Signature); } else { //
// Otherwise just mark the entry as free and put it back on the
// chunks free list.
#if DBG
memset(Entry, 0xCCCCCCCC, ChunkInfo->EntrySize); #endif
Entry->Flags = FLAG_ENTRY_ON_FREE_LIST; Entry->Signature = 0; InsertTailList(&Chunk->FreeEntryHead, &Entry->FreeEntryList); WmipLeaveSMCritSection(); } }
ULONG WmipUnreferenceEntry( PCHUNKINFO ChunkInfo, PENTRYHEADER Entry ) /*+++
Routine Description:
This routine will remove a reference count from the entry and if the reference count reaches zero then the entry is removed from its active list and then cleaned up and finally freed.
Arguments:
ChunkInfo points at structure that describes the entry
Entry is the entry to unreference
Return Value:
New refcount of the entry
---*/ { ULONG RefCount;
PAGED_CODE(); WmipAssert(Entry != NULL); WmipAssert(Entry->RefCount > 0); WmipAssert(Entry->Signature == ChunkInfo->Signature);
WmipEnterSMCritSection(); InterlockedDecrement(&Entry->RefCount); RefCount = Entry->RefCount;
if (RefCount == 0) { //
// Entry has reached a ref count of 0 so mark it as invalid and remove
// it from its active list.
Entry->Flags |= FLAG_ENTRY_INVALID;
if ((Entry->InUseEntryList.Flink != NULL) && (Entry->Flags & FLAG_ENTRY_REMOVE_LIST)) { RemoveEntryList(&Entry->InUseEntryList); }
WmipLeaveSMCritSection();
if (ChunkInfo->EntryCleanup != NULL) { //
// Call cleanup routine to free anything contained by the entry
(*ChunkInfo->EntryCleanup)(ChunkInfo, Entry); }
//
// Place the entry back on its free list
WmipFreeEntry(ChunkInfo, Entry); } else { WmipLeaveSMCritSection(); } return(RefCount); }
PWCHAR WmipCountedToSz( PWCHAR Counted ) { PWCHAR Sz; USHORT CountedLen;
PAGED_CODE(); CountedLen = *Counted++; Sz = WmipAlloc(CountedLen + sizeof(WCHAR)); if (Sz != NULL) { memcpy(Sz, Counted, CountedLen); Sz[CountedLen/sizeof(WCHAR)] = UNICODE_NULL; }
return(Sz); }
#ifdef HEAPVALIDATION
PVOID WmipAllocWithTag( ULONG Size, ULONG Tag ) { PVOID p;
PAGED_CODE();
p = ExAllocatePoolWithTag(PagedPool, Size, Tag);
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAlloc %x (%x)\n", p, Size));
return(p); }
PVOID WmipAlloc( ULONG Size ) { PVOID p;
PAGED_CODE(); p = ExAllocatePoolWithTag(PagedPool, Size, 'pimW');
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipAlloc %x (%x)\n", p, Size));
return(p); }
void WmipFree( PVOID p ) {
PAGED_CODE(); WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: WmipFree %x\n", p)); WmipAssert(p != NULL);
ExFreePool(p); } #endif
|