333 lines
8 KiB
C
333 lines
8 KiB
C
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright(C) 1997-1998 Microsoft Corporation all rights reserved.
|
||
|
//
|
||
|
// Module: iascompool.h
|
||
|
//
|
||
|
// Project: Everest
|
||
|
//
|
||
|
// Description: Object pool that uses CoTaskMemAlloc() / CoTaskMemFree()
|
||
|
//
|
||
|
// Author: TLP 11/11/97
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifndef __IAS_COM_MEMPOOL_H_
|
||
|
#define __IAS_COM_MEMPOOL_H_
|
||
|
|
||
|
// Assume another include has #included ias.h
|
||
|
#include <vector>
|
||
|
#include <list>
|
||
|
using namespace std;
|
||
|
|
||
|
#define COM_MEMPOOL_INITIALIZED 1
|
||
|
#define COM_MEMPOOL_UNINITIALIZED 0
|
||
|
|
||
|
//
|
||
|
// NOTE: m_lState must be aligned on 32 bit value or calls to
|
||
|
// InterlockedExchange will fail on multi-processor x86 systems.
|
||
|
|
||
|
template < class T, DWORD dwPerAllocT, bool bFixedSize >
|
||
|
class CComMemPool
|
||
|
{
|
||
|
// State flag - 1 = mem pool initialized, 0 = mem pool uninitialized
|
||
|
LONG m_lState;
|
||
|
// Total number of items allocated
|
||
|
DWORD m_dwCountTotal;
|
||
|
// Number of items on the free list
|
||
|
DWORD m_dwCountFree;
|
||
|
// Highest number of outstanding allocations
|
||
|
DWORD m_dwHighWater;
|
||
|
// Number of objects per system memory allocation
|
||
|
DWORD m_dwPerAllocT;
|
||
|
// Fixed size pool flag
|
||
|
bool m_bFixedSize;
|
||
|
// Critical Section - serializes free item list access
|
||
|
CRITICAL_SECTION m_CritSec;
|
||
|
// Memory block list
|
||
|
typedef list<PVOID> MemBlockList;
|
||
|
typedef MemBlockList::iterator MemBlockListIterator;
|
||
|
MemBlockList m_listMemBlocks;
|
||
|
// Free item list
|
||
|
typedef list<T*> FreeList;
|
||
|
typedef FreeList::iterator FreeListIterator;
|
||
|
FreeList m_listFreeT;
|
||
|
|
||
|
// Disallow copy and assignment
|
||
|
CComMemPool(const CComMemPool& theClass);
|
||
|
CComMemPool& operator=(const CComMemPool& theClass);
|
||
|
|
||
|
public:
|
||
|
|
||
|
//
|
||
|
// Constructor
|
||
|
//
|
||
|
CComMemPool()
|
||
|
: m_listMemBlocks(0),
|
||
|
m_listFreeT(0) // pre-alloc space for list nodes
|
||
|
{
|
||
|
m_lState = COM_MEMPOOL_UNINITIALIZED;
|
||
|
m_dwPerAllocT = dwPerAllocT;
|
||
|
m_bFixedSize = bFixedSize;
|
||
|
m_dwCountTotal = 0;
|
||
|
m_dwCountFree = 0;
|
||
|
m_dwHighWater = 0;
|
||
|
InitializeCriticalSection(&m_CritSec);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Destructor
|
||
|
//
|
||
|
~CComMemPool()
|
||
|
{
|
||
|
_ASSERT( COM_MEMPOOL_UNINITIALIZED == m_lState );
|
||
|
DeleteCriticalSection(&m_CritSec);
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Init() - Initialize the memory pool
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool Init(void)
|
||
|
{
|
||
|
bool bReturn = false;
|
||
|
|
||
|
if ( COM_MEMPOOL_UNINITIALIZED == InterlockedExchange(&m_lState, COM_MEMPOOL_INITIALIZED) )
|
||
|
{
|
||
|
if ( AllocateMemBlock() )
|
||
|
{
|
||
|
bReturn = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
InterlockedExchange(&m_lState, COM_MEMPOOL_UNINITIALIZED);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_ASSERTE(FALSE);
|
||
|
}
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Shutdown() - Shutdown the memory pool freeing any system resources used
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void Shutdown(void)
|
||
|
{
|
||
|
MemBlockListIterator p;
|
||
|
MemBlockListIterator q;
|
||
|
|
||
|
if ( COM_MEMPOOL_INITIALIZED == InterlockedExchange(&m_lState, COM_MEMPOOL_UNINITIALIZED) )
|
||
|
{
|
||
|
if ( m_dwCountTotal != m_dwCountFree )
|
||
|
{
|
||
|
// Still have blocks outstanding...
|
||
|
//
|
||
|
_ASSERTE( FALSE );
|
||
|
}
|
||
|
if ( ! m_listMemBlocks.empty() )
|
||
|
{
|
||
|
p = m_listMemBlocks.begin();
|
||
|
q = m_listMemBlocks.end();
|
||
|
while ( p != q )
|
||
|
{
|
||
|
CoTaskMemFree(*p);
|
||
|
p++;
|
||
|
}
|
||
|
m_listMemBlocks.clear();
|
||
|
}
|
||
|
m_dwCountTotal = 0;
|
||
|
m_dwCountFree = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// COM pool is not inititalized
|
||
|
//
|
||
|
_ASSERTE( FALSE );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Alloc() - Allocate an unitialized object from the pool
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
T* Alloc(void)
|
||
|
{
|
||
|
T* pMemBlk = NULL;
|
||
|
|
||
|
TraceFunctEnter("CComMemPool::Alloc()");
|
||
|
|
||
|
if ( COM_MEMPOOL_INITIALIZED == m_lState )
|
||
|
{
|
||
|
EnterCriticalSection(&m_CritSec);
|
||
|
if ( m_listFreeT.empty() )
|
||
|
{
|
||
|
if ( ! m_bFixedSize )
|
||
|
{
|
||
|
if ( AllocateMemBlock() )
|
||
|
{
|
||
|
pMemBlk = m_listFreeT.front();
|
||
|
m_listFreeT.pop_front();
|
||
|
m_dwCountFree--;
|
||
|
if ( m_dwHighWater < (m_dwCountTotal - m_dwCountFree) )
|
||
|
{
|
||
|
m_dwHighWater++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ErrorTrace(0,"Could not allocate memory!");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ErrorTrace(0,"Fixed size pool is exhausted!");
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pMemBlk = m_listFreeT.front();
|
||
|
m_listFreeT.pop_front();
|
||
|
m_dwCountFree--;
|
||
|
if ( m_dwHighWater < (m_dwCountTotal - m_dwCountFree) )
|
||
|
{
|
||
|
m_dwHighWater++;
|
||
|
}
|
||
|
}
|
||
|
LeaveCriticalSection(&m_CritSec);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ErrorTrace(0,"The memory pool is not initialized!");
|
||
|
_ASSERTE( FALSE );
|
||
|
}
|
||
|
if ( pMemBlk )
|
||
|
{
|
||
|
memset(pMemBlk, 0, sizeof(T));
|
||
|
new (pMemBlk) T(); // Placement new for class T - requires default contructor
|
||
|
}
|
||
|
TraceFunctLeave();
|
||
|
return pMemBlk;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Free() - Return an object to the memory pool
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void Free(T *pMemBlk)
|
||
|
{
|
||
|
TraceFunctEnter("CComMemPool::Free()");
|
||
|
if ( COM_MEMPOOL_INITIALIZED == m_lState )
|
||
|
{
|
||
|
pMemBlk->~T(); // Explicit call to destructor due to placement new
|
||
|
EnterCriticalSection(&m_CritSec);
|
||
|
m_listFreeT.insert(m_listFreeT.begin(),pMemBlk);
|
||
|
m_dwCountFree++;
|
||
|
LeaveCriticalSection(&m_CritSec);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ErrorTrace(0,"The memory pool is not initialized!");
|
||
|
_ASSERTE( FALSE );
|
||
|
}
|
||
|
TraceFunctLeave();
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Dump() - Dump the contents of the memory pool - Debug Service
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
void Dump(void)
|
||
|
{
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
UINT i;
|
||
|
MemBlockListIterator p;
|
||
|
FreeListIterator r;
|
||
|
FreeListIterator s;
|
||
|
|
||
|
TraceFunctEnter("CComMemPool::Dump()");
|
||
|
if ( COM_MEMPOOL_INITIALIZED == m_lState )
|
||
|
{
|
||
|
// Dump the counts
|
||
|
EnterCriticalSection(&m_CritSec);
|
||
|
DebugTrace(0,"m_dwCountTotal = %d", m_dwCountTotal);
|
||
|
DebugTrace(0,"m_dwCountFree = %d", m_dwCountFree);
|
||
|
DebugTrace(0,"m_dwHighWater = %d", m_dwHighWater);
|
||
|
// Dump the pointers to memory blocks
|
||
|
DebugTrace(0,"m_listMemBlocks.size() = %d", m_listMemBlocks.size());
|
||
|
p = m_listMemBlocks.begin();
|
||
|
i = 0;
|
||
|
while ( p != m_listMemBlocks.end() )
|
||
|
{
|
||
|
DebugTrace(0,"m_listMemBlocks block %d = $%p", i, *p);
|
||
|
i++;
|
||
|
p++;
|
||
|
}
|
||
|
// Dump the pointers to items
|
||
|
DebugTrace(0,"CComMemPool::Dump() - m_listFreeT.size() = %d", m_listFreeT.size());
|
||
|
r = m_listFreeT.begin();
|
||
|
i = 0;
|
||
|
while ( r != m_listFreeT.end() )
|
||
|
{
|
||
|
DebugTrace(0,"CComMemPool::Dump() - m_listFreeT item %d = $%p", i, *r);
|
||
|
i++;
|
||
|
r++;
|
||
|
}
|
||
|
LeaveCriticalSection(&m_CritSec);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ErrorTrace(0,"The memory pool is not initialized!");
|
||
|
_ASSERTE( FALSE );
|
||
|
}
|
||
|
TraceFunctLeave();
|
||
|
#endif // DEBUG
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
private:
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// AllocateMemBlock() - Allocate some system memory and chop it into
|
||
|
// T sized blocks
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool AllocateMemBlock()
|
||
|
{
|
||
|
|
||
|
bool bReturn = false;
|
||
|
UINT i;
|
||
|
UINT uBlkSize;
|
||
|
T* lpMemBlock;
|
||
|
|
||
|
TraceFunctEnter("CComMemPool::AllocateMemBlock()");
|
||
|
uBlkSize = m_dwPerAllocT * sizeof(T);
|
||
|
lpMemBlock = (T*) CoTaskMemAlloc(uBlkSize);
|
||
|
if ( lpMemBlock )
|
||
|
{
|
||
|
memset(lpMemBlock, 0, uBlkSize);
|
||
|
m_listMemBlocks.insert(m_listMemBlocks.begin(), (PVOID)lpMemBlock);
|
||
|
// Chop up the newly allocated memory block into sizeof(T) sized elements and place
|
||
|
// the elements on the list of pointers to Ts.
|
||
|
for ( i = 0; i < m_dwPerAllocT; i++ )
|
||
|
{
|
||
|
m_listFreeT.insert(m_listFreeT.end(),lpMemBlock);
|
||
|
lpMemBlock++;
|
||
|
}
|
||
|
// Update the pool memory use variables
|
||
|
m_dwCountTotal += m_dwPerAllocT;
|
||
|
m_dwCountFree += m_dwPerAllocT;
|
||
|
bReturn = true;
|
||
|
}
|
||
|
TraceFunctLeave();
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
}; // End of CComMemPool
|
||
|
|
||
|
|
||
|
#endif // __IAS_COM_MEMPOOL_H_
|