You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
7.7 KiB
321 lines
7.7 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: fixedpool.cpp
|
|
* Content: fixed size pool manager
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ====== == ======
|
|
* 07-21-2001 masonb Created
|
|
* 10-16-2001 vanceo Tweaked release locking and freed memory if Alloc function fails
|
|
* 02-22-2002 simonpow Removed c'tor and d'tor, which weren't consistently being called
|
|
***************************************************************************/
|
|
|
|
#include "dncmni.h"
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::Initialize"
|
|
BOOL CFixedPool::Initialize(DWORD dwElementSize,
|
|
FN_BLOCKALLOC pfnBlockAlloc,
|
|
FN_BLOCKGET pfnBlockGet,
|
|
FN_BLOCKRELEASE pfnBlockRelease,
|
|
FN_BLOCKDEALLOC pfnBlockDeAlloc)
|
|
{
|
|
|
|
// Ensure that we stay heap aligned for SLISTs
|
|
#ifdef _WIN64
|
|
DBG_CASSERT(sizeof(FIXED_POOL_ITEM) % 16 == 0);
|
|
#else // !_WIN64
|
|
DBG_CASSERT(sizeof(FIXED_POOL_ITEM) % 8 == 0);
|
|
#endif // _WIN64
|
|
|
|
#ifdef DBG
|
|
if (!DNInitializeCriticalSection(&m_csInUse))
|
|
{
|
|
DPFERR("Failed initializing pool critical section");
|
|
m_fInitialized = FALSE;
|
|
return FALSE;
|
|
}
|
|
m_pInUseElements = NULL;
|
|
#endif // DBG
|
|
|
|
DNInitializeSListHead(&m_slAvailableElements);
|
|
|
|
m_pfnBlockAlloc = pfnBlockAlloc;
|
|
m_pfnBlockGet = pfnBlockGet;
|
|
m_pfnBlockRelease = pfnBlockRelease;
|
|
m_pfnBlockDeAlloc = pfnBlockDeAlloc;
|
|
m_dwItemSize = dwElementSize;
|
|
|
|
#ifdef DBG
|
|
m_lAllocated = 0;
|
|
#endif // DBG
|
|
m_lInUse = 0;
|
|
m_fInitialized = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::DeInitialize"
|
|
VOID CFixedPool::DeInitialize()
|
|
{
|
|
FIXED_POOL_ITEM* pItem;
|
|
DNSLIST_ENTRY* pslEntry;
|
|
|
|
if (m_fInitialized == FALSE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Clean up entries sitting in the pool
|
|
pslEntry = DNInterlockedPopEntrySList(&m_slAvailableElements);
|
|
while(pslEntry != NULL)
|
|
{
|
|
pItem = CONTAINING_RECORD(pslEntry, FIXED_POOL_ITEM, slist);
|
|
|
|
if (m_pfnBlockDeAlloc != NULL)
|
|
{
|
|
(*m_pfnBlockDeAlloc)(pItem + 1);
|
|
}
|
|
DNFree(pItem);
|
|
|
|
#ifdef DBG
|
|
DNInterlockedDecrement(&m_lAllocated);
|
|
DNASSERT(m_lAllocated >=0);
|
|
#endif // DBG
|
|
|
|
pslEntry = DNInterlockedPopEntrySList(&m_slAvailableElements);
|
|
}
|
|
|
|
#ifdef DBG
|
|
DumpLeaks();
|
|
DNDeleteCriticalSection(&m_csInUse);
|
|
#endif // DBG
|
|
|
|
m_fInitialized = FALSE;
|
|
}
|
|
|
|
|
|
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::Preallocate"
|
|
DWORD CFixedPool::Preallocate( DWORD dwCount, PVOID pvContext )
|
|
{
|
|
DWORD dwAllocated;
|
|
FIXED_POOL_ITEM* pItem;
|
|
|
|
DNASSERT(m_fInitialized == TRUE);
|
|
|
|
for(dwAllocated = 0; dwAllocated < dwCount; dwAllocated++)
|
|
{
|
|
pItem = (FIXED_POOL_ITEM*)DNMalloc(sizeof(FIXED_POOL_ITEM) + m_dwItemSize);
|
|
if (pItem == NULL)
|
|
{
|
|
DPFERR("Out of memory allocating new item for pool");
|
|
return NULL;
|
|
}
|
|
|
|
if ((m_pfnBlockAlloc != NULL) && !(*m_pfnBlockAlloc)(pItem + 1, pvContext))
|
|
{
|
|
DPFERR("Alloc function returned FALSE allocating new item for pool");
|
|
|
|
// Can't stick the new item as available in the pool since pool assumes Alloc has
|
|
// succeeded when it's in the pool.
|
|
DNFree(pItem);
|
|
break;
|
|
}
|
|
|
|
#ifdef DBG
|
|
DNInterlockedIncrement(&m_lAllocated);
|
|
#endif // DBG
|
|
|
|
DNInterlockedPushEntrySList(&m_slAvailableElements, &pItem->slist);
|
|
}
|
|
|
|
return dwAllocated;
|
|
}
|
|
|
|
#endif // DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::Get"
|
|
VOID* CFixedPool::Get( PVOID pvContext )
|
|
{
|
|
FIXED_POOL_ITEM* pItem;
|
|
DNSLIST_ENTRY* pslEntry;
|
|
|
|
DNASSERT(m_fInitialized == TRUE);
|
|
|
|
pslEntry = DNInterlockedPopEntrySList(&m_slAvailableElements);
|
|
if (pslEntry == NULL)
|
|
{
|
|
#ifdef DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
DPFX(DPFPREP, 0, "No more items in pool!");
|
|
DNASSERTX(! "No more items in pool!", 2);
|
|
return NULL;
|
|
#else // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
pItem = (FIXED_POOL_ITEM*)DNMalloc(sizeof(FIXED_POOL_ITEM) + m_dwItemSize);
|
|
if (pItem == NULL)
|
|
{
|
|
DPFERR("Out of memory allocating new item for pool!");
|
|
return NULL;
|
|
}
|
|
|
|
if ((m_pfnBlockAlloc != NULL) && !(*m_pfnBlockAlloc)(pItem + 1, pvContext))
|
|
{
|
|
DPFERR("Alloc function returned FALSE allocating new item for pool!");
|
|
|
|
// Can't stick the new item as available in the pool since pool assumes Alloc has
|
|
// succeeded when it's in the pool.
|
|
DNFree(pItem);
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef DBG
|
|
DNInterlockedIncrement(&m_lAllocated);
|
|
#endif // DBG
|
|
#endif // ! DPNBUILD_PREALLOCATEDMEMORYMODEL
|
|
}
|
|
else
|
|
{
|
|
pItem = CONTAINING_RECORD(pslEntry, FIXED_POOL_ITEM, slist);
|
|
}
|
|
|
|
// At this point we have an item whether it was newly created or pulled from the pool.
|
|
|
|
InterlockedIncrement(&m_lInUse);
|
|
DNASSERT(m_lInUse > 0);
|
|
#ifdef DBG
|
|
// Note the callstack and add the item to the in use list.
|
|
pItem->callstack.NoteCurrentCallStack();
|
|
|
|
DNEnterCriticalSection(&m_csInUse);
|
|
pItem->slist.Next = m_pInUseElements;
|
|
m_pInUseElements = &pItem->slist;
|
|
DNLeaveCriticalSection(&m_csInUse);
|
|
|
|
// In debug only, store the pool the item belongs to on the item for checking upon release
|
|
pItem->pThisPool = this;
|
|
#endif // DBG
|
|
|
|
if (m_pfnBlockGet != NULL)
|
|
{
|
|
(*m_pfnBlockGet)(pItem + 1, pvContext);
|
|
}
|
|
|
|
return (pItem + 1);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::Release"
|
|
VOID CFixedPool::Release(VOID* pvItem)
|
|
{
|
|
FIXED_POOL_ITEM* pItem;
|
|
|
|
DNASSERT(m_fInitialized == TRUE);
|
|
DNASSERT(pvItem != NULL);
|
|
|
|
pItem = (FIXED_POOL_ITEM*)pvItem - 1;
|
|
|
|
#ifdef DBG
|
|
// Make sure the item comes from this pool.
|
|
// If the item has already been released, pThisPool will be NULL.
|
|
DNASSERT(pItem->pThisPool == this);
|
|
#endif // DBG
|
|
|
|
if (m_pfnBlockRelease != NULL)
|
|
{
|
|
(*m_pfnBlockRelease)(pvItem);
|
|
}
|
|
|
|
#ifdef DBG
|
|
// Remove the item from the in use list.
|
|
DNEnterCriticalSection(&m_csInUse);
|
|
if (m_pInUseElements == &pItem->slist)
|
|
{
|
|
// Easy case, just reset m_pInUseElements to the next item in the list.
|
|
m_pInUseElements = pItem->slist.Next;
|
|
}
|
|
else
|
|
{
|
|
DNSLIST_ENTRY* pslEntry;
|
|
|
|
// We need to run the list and look for it
|
|
pslEntry = m_pInUseElements;
|
|
while (pslEntry != NULL)
|
|
{
|
|
if (pslEntry->Next == &pItem->slist)
|
|
{
|
|
// Found it, pull it out.
|
|
pslEntry->Next = pItem->slist.Next;
|
|
break;
|
|
}
|
|
pslEntry = pslEntry->Next;
|
|
}
|
|
}
|
|
|
|
DNLeaveCriticalSection(&m_csInUse);
|
|
#endif // DBG
|
|
DNASSERT(m_lInUse != 0);
|
|
InterlockedDecrement(&m_lInUse);
|
|
|
|
DNInterlockedPushEntrySList(&m_slAvailableElements, &pItem->slist);
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::GetInUseCount"
|
|
DWORD CFixedPool::GetInUseCount( void )
|
|
{
|
|
DNASSERT(m_fInitialized == TRUE);
|
|
|
|
return m_lInUse;
|
|
}
|
|
|
|
#ifdef DBG
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CFixedPool::DumpLeaks"
|
|
VOID CFixedPool::DumpLeaks()
|
|
{
|
|
// NOTE: It is important that this be a separate function because it consumes so much stack space.
|
|
FIXED_POOL_ITEM* pItem;
|
|
DNSLIST_ENTRY* pslEntry;
|
|
TCHAR szCallStackBuffer[ CALLSTACK_BUFFER_SIZE ];
|
|
|
|
// Report any leaked items
|
|
if(m_lAllocated)
|
|
{
|
|
DNASSERT(m_lInUse == m_lAllocated);
|
|
DNASSERT(m_pInUseElements != NULL);
|
|
|
|
DPFX(DPFPREP, 0, "(%p) Pool leaking %d items", this, m_lAllocated);
|
|
|
|
pslEntry = m_pInUseElements;
|
|
while(pslEntry != NULL)
|
|
{
|
|
pItem = CONTAINING_RECORD(pslEntry, FIXED_POOL_ITEM, slist);
|
|
|
|
pItem->callstack.GetCallStackString( szCallStackBuffer );
|
|
|
|
DPFX(DPFPREP, 0, "(%p) Pool item leaked at address %p (user pointer: %p)\n%s", this, pItem, pItem + 1, szCallStackBuffer );
|
|
|
|
pslEntry = pslEntry->Next;
|
|
}
|
|
|
|
DNASSERT(0);
|
|
}
|
|
else
|
|
{
|
|
DNASSERT(m_pInUseElements == NULL);
|
|
DNASSERT(m_lInUse == 0);
|
|
}
|
|
|
|
|
|
}
|
|
#endif // DBG
|