Leaked source code of windows server 2003
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

/*==========================================================================
*
* 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