windows-nt/Source/XPSP1/NT/base/ntos/wmi/chunk.c

382 lines
8.7 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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