/*=================================================================== Microsoft Denali Microsoft Confidential. Copyright 1996 Microsoft Corporation. All Rights Reserved. Component: List Allocater Template File: Listmgr.h Owner: PramodD This is the List Allocator template header file. It manages memory requests by allocating from a array/linklist. The size of the initial array is a parameter to the constructor. ===================================================================*/ #ifndef LISTMGR_H #define LISTMGR_H #ifdef PAGESIZE #undef PAGESIZE #endif #define PAGESIZE 4096 // Allocation unit template class CListElem { private: T m_Element; // The actual element we want to allocate T * m_pNext; // Next element in free list public: void SetNext(CListElem * element); T * GetNext(void); }; // Member access functions template inline void CListElem::SetNext(CListElem * element) { m_pNext = (T *) element; } template inline T * CListElem::GetNext( void ) { return m_pNext; } // Single Threaded List Manager template class CSTList { private: CListElem * m_pFreeHead; CListElem * m_pAllocHead; UINT m_cFree; UINT m_cUsed; UINT m_cSize; public: CSTList(void); private: void MakeLinks(CListElem * TArray, UINT cSize); HRESULT GrabMemory(UINT cSize); public: HRESULT Init(UINT cSize=0); // Initial allocation HRESULT UnInit(void); // Release memory T * Allocate(void); // Allocate one element T * ReAlloc(UINT cSize=0); // Allocate memory if needed void Free( T * element ); // Free one element UINT FreeCount(void); // Number of free elements UINT UsedCount(void); // Number of used elements UINT Size(void); // Number of elements }; // Constructor template CSTList::CSTList( void ) { m_pFreeHead = NULL; m_pAllocHead = NULL; m_cFree = 0; m_cUsed = 0; m_cSize = 0; } template void CSTList::MakeLinks( CListElem *TArray, UINT cSize ) { CListElem * pT = TArray; UINT i = 0; m_cSize += cSize; m_cFree += cSize; // Initialize link list while ( i < cSize - 1 ) { pT->SetNext( pT + 1 ); pT++; i++; } if ( m_pFreeHead ) pT->SetNext( m_pFreeHead ); else pT->SetNext( pT + 1 ); m_pFreeHead = TArray; } template HRESULT CSTList::GrabMemory( UINT cSize ) { CListElem * pT; UINT cT; if ( cSize ) cT = cSize; else cT = PAGESIZE/sizeof(CListElem); if ( pT = (CListElem *) GlobalAlloc( GPTR, sizeof( CListElem ) * (cT + 1) ) ) { pT->SetNext( m_pAllocHead ); m_pAllocHead = pT; pT++; MakeLinks( pT, cT ); return S_OK; } return E_FAIL; } // Initialization template inline HRESULT CSTList::Init( UINT cSize = 0 ) { return GrabMemory( cSize ); } // Free all memory, All allocated elements should have been // returned to the list. Otherwise it returns E_FAIL. template HRESULT CSTList::UnInit( void ) { HRESULT hr = S_OK; CListElem * pT; // Free all the memory while ( m_pAllocHead ) { pT = (CListElem *) m_pAllocHead->GetNext(); GlobalFree( (HGLOBAL) m_pAllocHead ); m_pAllocHead = pT; } m_pFreeHead = NULL; // Check for memory leaks if ( m_cSize != m_cFree ) hr = E_FAIL; m_cSize = 0; m_cFree = 0; m_cUsed = 0; return hr; } // Allocate element from array template T * CSTList::Allocate( void ) { if ( m_cFree == 0 ) return NULL; CListElem * pT = m_pFreeHead; m_pFreeHead = (CListElem *) pT->GetNext(); pT->SetNext( NULL ); m_cFree--; m_cUsed++; return (T *) pT; } // Allocate element from array, get more memory if needed template T * CSTList::ReAlloc( UINT cSize = 0 ) { if ( m_cFree == 0 ) GrabMemory(cSize); return Allocate(); } // Return element to array template void CSTList::Free( T *element ) { if ( element == NULL || m_cUsed == 0 ) return; CListElem * pT = (CListElem *) element; if ( pT->GetNext() == NULL ) { pT->SetNext( m_pFreeHead ); m_pFreeHead = pT; m_cUsed--; m_cFree++; } } // Member access functions template inline UINT CSTList::FreeCount( void ) { return m_cFree; } template inline UINT CSTList::UsedCount( void ) { return m_cUsed; } template inline UINT CSTList::Size( void ) { return m_cSize; } // Multi Threaded List Manager template class CMTList: private CSTList { // Synchronization objects private: BOOL m_fInited; CRITICAL_SECTION m_csList; HANDLE m_hBlockedReaders; HANDLE m_hBlockedWriters; // Counters private: int m_cActiveReaders; int m_cWaitingReaders; int m_cActiveWriters; int m_cWaitingWriters; // Public constructor and destructor public: CMTList(void) { m_fInited = FALSE; } virtual ~CMTList( void ); // Private synchronization functions private: void ReadLock(void); // Lock List access for read void WriteLock(void); // Lock List access for write void ReleaseReadLock(void); // Unlock read access void ReleaseWriteLock(void); // Unlock write access // Public List functions public: HRESULT Init( int cSize = 0 );// Initial allocation HRESULT UnInit(void); // Free all memory T * Allocate(void); // Allocate one element T * ReAlloc(UINT cSize=0); // Allocate more memory if needed void Free(T *element); // Free one element UINT FreeCount(void); // Number of free elements UINT UsedCount(void); // Number of used elements UINT Size(void); // Total number of elements }; template HRESULT CMTList::Init( int cSize = 0 ) { HRESULT hr; // Initialize synchronization objects ErrInitCriticalSection( &m_csList, hr ); if ( FAILED( hr ) ) return hr; m_hBlockedReaders = IIS_CREATE_SEMAPHORE( "CMTList::m_hBlockedReaders", this, 0L, 9999L ); m_hBlockedWriters = IIS_CREATE_SEMAPHORE( "CMTList::m_hBlockedWriters", this, 0L, 9999L ); if ( m_hBlockedReaders && m_hBlockedWriters ) { // Initialize counters m_cActiveReaders = 0; m_cWaitingReaders = 0; m_cActiveWriters = 0; m_cWaitingWriters = 0; m_fInited = TRUE; if ( SUCCEEDED( CSTList::Init(cSize) ) ) return S_OK; } return E_FAIL; } template HRESULT CMTList::UnInit( void ) { if ( !m_fInited ) return E_FAIL; WriteLock(); HRESULT hr = CSTList::UnInit(); ReleaseWriteLock(); return hr; } template CMTList::~CMTList( void ) { if ( m_fInited ) { // Destroy synchronization objects DeleteCriticalSection( &m_csList ); CloseHandle( m_hBlockedReaders ); CloseHandle( m_hBlockedWriters ); } } template void CMTList::ReadLock( void ) { if ( !m_fInited ) return; EnterCriticalSection( &m_csList ); if ( m_cActiveWriters > 0 || m_cWaitingWriters > 0 ) { m_cWaitingReaders++; LeaveCriticalSection( &m_csList ); WaitForSingleObject( m_hBlockedReaders, INFINITE ); } else { m_cActiveReaders++; LeaveCriticalSection( &m_csList ); } } template void CMTList::ReleaseReadLock( void ) { if ( !m_fInited ) return; EnterCriticalSection( &m_csList ); m_cActiveReaders--; if ( m_cActiveReaders == 0 && m_cWaitingWriters > 0 ) { m_cActiveWriters = 1; m_cWaitingWriters = 0; ReleaseSemaphore( m_hBlockedWriters, 1, NULL ); } LeaveCriticalSection( &m_csList ); } template void CMTList::WriteLock( void ) { if ( !m_fInited ) return; EnterCriticalSection( &m_csList ); if ( m_cActiveReaders == 0 && m_cActiveWriters == 0 ) { m_cActiveWriters = 1; LeaveCriticalSection( &m_csList ); } else { m_cWaitingWriters++; LeaveCriticalSection( &m_csList ); WaitForSingleObject( m_hBlockedWriters, INFINITE ); } } template void CMTList::ReleaseWriteLock( void ) { if ( !m_fInited ) return; EnterCriticalSection( &m_csList ); m_cActiveWriters = 0; if ( m_cWaitingReaders > 0 ) { m_cActiveReaders = m_cWaitingReaders; m_cWaitingReaders = 0; ReleaseSemaphore( m_hBlockedReaders, m_cActiveReaders, NULL ); } else if ( m_cWaitingWriters > 0 ) { m_cWaitingWriters--; ReleaseSemaphore( m_hBlockedWriters, 1, NULL ); } LeaveCriticalSection( &m_csList ); } template T * CMTList::Allocate( void ) { if ( !m_fInited ) return NULL; WriteLock(); T * retVal = CSTList::Allocate(); ReleaseWriteLock(); return retVal; } template T * CMTList::ReAlloc( UINT cSize = 0 ) { if ( !m_fInited ) return NULL; WriteLock(); T * retVal = CSTList::ReAlloc( cSize ); ReleaseWriteLock(); return retVal; } template void CMTList::Free( T *element ) { if ( !m_fInited ) return; WriteLock(); CSTList::Free( element ); ReleaseWriteLock(); } template UINT CMTList::FreeCount( void ) { if ( !m_fInited ) return 0; ReadLock(); UINT retVal = CSTList::FreeCount(); ReleaseReadLock(); return retVal; } template UINT CMTList::UsedCount( void ) { if ( !m_fInited ) return 0; ReadLock(); UINT retVal = CSTList::UsedCount(); ReleaseReadLock(); return retVal; } template UINT CMTList::Size( void ) { if ( !m_fInited ) return 0; ReadLock(); UINT retVal = CSTList::Size(); ReleaseReadLock(); return retVal; } #endif // LISTMGR_H