|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1994.
//
// File: freelist.cxx
//
// Contents: CFreeList implementations
//
// History: 07-Jul-94 BobDay Created
//
//----------------------------------------------------------------------------
#include "headers.cxx"
#pragma hdrstop
//
// Each element, when it is free, has a pointer stored within it that
// points to the next free element. We can do this because we know that
// the element is free, all of its data is unused. These pointers are used
// as DWORDs since they can be virtual pointers (16:16).
//
#define CALC_NEXTPTR(lpElement) \
((LPDWORD)((DWORD)(lpElement) + m_iNextPtrOffset))
//
// Each block of elements has a pointer to the next block of elements. We
// allocate extra room for this pointer just after all of the elements within
// the block. These pointers are used as DWORDs since they can be virtual
// pointers (16:16).
#define CALC_BLOCKNEXTPTR(lpBlock,dwElementSectionSize) \
((LPDWORD)((DWORD)(lpBlock) + (dwElementSectionSize)))
//
// Here are our global free lists, created on DLL load
// The block sizes are generally -1 to allow space for block
// list overhead
//
CFreeList flFreeList16( // THUNK1632OBJ free list
&mmodel16Public, sizeof(THUNK1632OBJ), 63, FIELD_OFFSET(THUNK1632OBJ, pphHolder));
CFreeList flFreeList32( // THUNK3216OBJ free list
&mmodel32, sizeof(THUNK3216OBJ), 63, FIELD_OFFSET(THUNK3216OBJ, pphHolder));
CFreeList flHolderFreeList( // PROXYHOLDER free list
&mmodel32, sizeof(PROXYHOLDER), 63, FIELD_OFFSET(PROXYHOLDER, dwFlags));
CFreeList flRequestFreeList( // IID request free list
&mmodel32, sizeof(IIDNODE), 7, FIELD_OFFSET(IIDNODE, pNextNode));
//+---------------------------------------------------------------------------
//
// Method: CFreeList::CFreeList
//
// Arguments: pmm - Memory model to use
// iElementSize - The size of the structure being made into a
// free list. e.g. sizeof THUNK1632OBJ
// iElementsPerBlock - How many elements to allocate at a time
// (a block contains this many elements).
// iNextPtrOffset - Offset within the element's structure for
// the place to store the free list's next
// element pointer. Sometimes (for debugging,
// etc.) it is desirable to make this NOT 0
// (the beginning of the element structure).
//
// Synopsis: constructor for CFreeList class
//
// History: 6-01-94 JohannP (Johann Posch) Created
// 7-05-94 BobDay (Bob Day) Changed it to be list based
//
//----------------------------------------------------------------------------
CFreeList::CFreeList( CMemoryModel *pmm, UINT iElementSize, UINT iElementsPerBlock, UINT iNextPtrOffset ) { //
// Save away the allocator information
//
m_pmm = pmm; m_iElementSize = iElementSize; m_iElementsPerBlock = iElementsPerBlock; m_iNextPtrOffset = iNextPtrOffset;
//
// Set the list of elements to empty
//
m_dwHeadElement = 0; m_dwTailElement = 0;
//
// Set the list of blocks to empty
//
m_dwHeadBlock = 0; }
//+---------------------------------------------------------------------------
//
// Method: CFreeList::AllocElement
//
// Synopsis: Allocates an element from the various blocks of elements
// and allocates a new block if necessary.
//
// Returns: 0 if failed to alloc an element,
// otherwise the DWORD representing the alloc'd element.
//
// History: 7-05-94 BobDay (Bob Day) Created
//
//----------------------------------------------------------------------------
DWORD CFreeList::AllocElement( void ) { DWORD dwNewHeadBlock; DWORD dwElementSectionSize; DWORD dwBlockSize; LPVOID lpBlock; UINT iCnt; DWORD dwElement; LPVOID lpElement; LPDWORD lpElementNextPtr;
//
// If the list of available elements is empty, callback to the derived
// class and make them add an entire new block of elements.
//
if ( m_dwHeadElement == 0 ) { //
// Allocate a new block
//
iCnt = m_iElementsPerBlock; dwElementSectionSize = m_iElementSize * m_iElementsPerBlock;
//
// Here we allocate an extra DWORD so that we can store in the block
// the address of the next block. In this way we have a list of
// blocks so that when the time comes to free them, we can find them
// all.
//
dwBlockSize = dwElementSectionSize + sizeof(DWORD);
dwNewHeadBlock = m_pmm->AllocMemory( dwBlockSize );
if ( dwNewHeadBlock == 0 ) { //
// Yikes, the block allocator failed!
//
thkDebugOut((DEB_ERROR, "CFreeList::AllocElement, AllocMemory failed\n")); return 0; } //
// Now initialize the block and link it into the block list.
//
lpBlock = m_pmm->ResolvePtr( dwNewHeadBlock, dwBlockSize ); if ( lpBlock == NULL ) { //
// Couldn't get a pointer to the block, some memory mapping
// problem?
//
thkDebugOut((DEB_ERROR, "CFreeList::AllocElement, " "ResolvePtr for block failed " "for address %08lX, size %08lX\n", dwNewHeadBlock, dwBlockSize )); // Try to return bad block to pool
m_pmm->FreeMemory( dwNewHeadBlock ); return 0; }
#if DBG == 1
// 0xDE = Alloc'd but not init'd
memset( lpBlock, 0xDE, dwBlockSize ); #endif
//
// Make this block point to the previous block
//
*CALC_BLOCKNEXTPTR(lpBlock,dwElementSectionSize) = m_dwHeadBlock; m_dwHeadBlock = dwNewHeadBlock; // Update block list
m_pmm->ReleasePtr(dwNewHeadBlock);
//
// Now initialize all of the elements within the block to be free.
//
// The below loop skips the first element, free's all of the remaining
// ones. This way we can return the first one and all of the rest will
// be in accending order; The order doesn't really matter, but its
// nice.
//
dwElement = dwNewHeadBlock;
while ( iCnt > 1 ) // Free n-1 items (we skip the first)
{ --iCnt; dwElement += m_iElementSize; // Skip to next one (miss 1st one)
FreeElement( dwElement ); }
dwElement = dwNewHeadBlock; // Use the first one as our alloc'd one
} else { // We better have some blocks by now
thkAssert( m_dwHeadBlock != 0 );
// Better have a "end of list" too!
thkAssert( m_dwTailElement != 0 );
//
// Grab an available element off the top (head) of the list.
//
dwElement = m_dwHeadElement;
lpElement = m_pmm->ResolvePtr( dwElement, m_iElementSize ); if ( lpElement == NULL ) { //
// Yikes, we weren't able to get a pointer to the element!
//
thkDebugOut((DEB_ERROR, "CFreeList::AllocElement, " "ResolvePtr for element failed " "for address %08lX, size %08lX\n", dwElement, m_iElementSize )); return 0; }
//
// Update the list to reflect the fact that we just removed the head
// and replace it with the one which was pointed to by the head.
//
lpElementNextPtr = CALC_NEXTPTR(lpElement); m_dwHeadElement = *lpElementNextPtr;
m_pmm->ReleasePtr(dwElement);
//
// Also, if we are now at the end of the list, then the tail element
// should point to nowhere (i.e. there is nothing to insert after).
//
if ( m_dwHeadElement == 0 ) { m_dwTailElement = 0; } }
#if DBG == 1
// Erase the memory being returned to highlight reuse of dead values
lpElement = m_pmm->ResolvePtr( dwElement, m_iElementSize ); memset( lpElement, 0xED, m_iElementSize ); m_pmm->ReleasePtr(dwElement);
thkDebugOut((DEB_ITRACE, "CFreeList::AllocElement, allocated element at %08lX\n", dwElement )); #endif
return dwElement; }
//+---------------------------------------------------------------------------
//
// Method: CFreeList::FreeElement
//
// Synopsis: Un-Allocates an element from the various blocks of elements,
// basically put the element back on the free list.
//
// Arguments: dwElement - Element to free
//
// Returns: -none- Asserts if failed.
//
// History: 7-05-94 BobDay (Bob Day) Created
//
//----------------------------------------------------------------------------
void CFreeList::FreeElement( DWORD dwElement ) { LPVOID lpElement; LPDWORD lpElementNextPtr; DWORD dwResolved;
//
// First, make sure we can set this new element's next element pointer
// to zero (he's going to be a the end of the list).
//
lpElement = m_pmm->ResolvePtr( dwElement, m_iElementSize ); if ( lpElement == NULL ) { //
// Yikes, we couldn't get a pointer to this element's place to store
// its next pointer.
//
thkDebugOut((DEB_ERROR, "CFreeList::FreeElement, " "ResolvePtr failed for free'd element\n" "for address %08lX, size %08lX\n", dwElement, m_iElementSize )); thkAssert(FALSE && "CFreeList::FreeElement, " "Resolve Ptr failed for free'd element\n"); return; }
#if DBG == 1
// Fill memory so its values can't be reused
if ( fZapProxy ) // Not doing this is important for
// the "PrepareForCleanup" processing the OLE32
// does on thread detach. ZapProxy can be used
// to turn it back on.
{ memset(lpElement, 0xDD, m_iElementSize); } #endif
lpElementNextPtr = CALC_NEXTPTR(lpElement);
*lpElementNextPtr = 0; // Zap his next pointer since he'll be on the end
m_pmm->ReleasePtr(dwElement);
//
// Add this element back onto the end (tail) of the list.
//
if ( m_dwTailElement == 0 ) { //
// Well, the list was empty, time to set it up
//
thkAssert( m_dwHeadElement == 0 );
lpElementNextPtr = &m_dwHeadElement; dwResolved = 0; } else { //
// Ok, the list wasn't empty, so we add this new one onto the end.
//
thkAssert( m_dwHeadElement != 0 );
dwResolved = m_dwTailElement; lpElement = m_pmm->ResolvePtr( m_dwTailElement, m_iElementSize ); if ( lpElement == NULL ) { //
// Oh no, we couldn't get a pointer to the next element pointer for
// the guy who is currently the tail of the list.
//
thkDebugOut((DEB_ERROR, "CFreeList::FreeElement, " "ResolvePtr failed for last element\n" "for address %08lX, size %08lX\n", m_dwTailElement, m_iElementSize )); thkAssert(FALSE && "CFreeList::FreeElement, " "Resolve Ptr failed for last element\n"); return; }
lpElementNextPtr = CALC_NEXTPTR(lpElement); }
//
// Update our tail pointer to point to our newly free'd guy.
//
m_dwTailElement = dwElement;
//
// Make the last guy point to this newly free'd guy
//
*lpElementNextPtr = dwElement;
if (dwResolved != 0) { m_pmm->ReleasePtr(dwResolved); }
thkDebugOut((DEB_ITRACE, "CFreeList::FreeElement, free'd element at %08lX\n", dwElement )); }
//+---------------------------------------------------------------------------
//
// Method: CFreeList::FreeMemoryBlocks
//
// Arguments: -none-
//
// Returns: -nothing-
//
// Synopsis: Called by derived destructors to allow them to free up their
// contents before going away.
//
// History: 7-05-94 BobDay (Bob Day) Created it
//
//----------------------------------------------------------------------------
void CFreeList::FreeMemoryBlocks( void ) { DWORD dwBlock; DWORD dwElementSectionSize; DWORD dwBlockSize; DWORD dwNextBlock; LPVOID lpBlock;
//
// Compute some constants for this list ahead of time
//
dwElementSectionSize = m_iElementSize * m_iElementsPerBlock;
//
// Add room for that extra DWORD, block next pointer. (See comment in
// AllocElement where it allocates an extra DWORD)
//
dwBlockSize = dwElementSectionSize + sizeof(DWORD);
//
// Iterate through the list of blocks free'ing them
//
dwBlock = m_dwHeadBlock;
while( dwBlock != 0 ) { //
// Find the next block ptr
//
lpBlock = m_pmm->ResolvePtr( dwBlock, dwBlockSize ); if ( lpBlock == NULL ) { //
// If we get an error here, we just drop out of loop
//
dwNextBlock = 0; } else { dwNextBlock = *CALC_BLOCKNEXTPTR(lpBlock,dwElementSectionSize);
#if DBG == 1
memset(lpBlock, 0xEE, dwBlockSize); #endif
m_pmm->ReleasePtr(dwBlock); m_pmm->FreeMemory( dwBlock ); } dwBlock = dwNextBlock; }
m_dwHeadElement = 0; m_dwTailElement = 0; m_dwHeadBlock = 0; }
|