|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1994.
//
// File: smalloc.cxx
//
// Contents: Shared memory heap implementation
//
// Classes:
//
// Functions:
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
// 10-May-95 KentCe Defer Heap Destruction to the last
// process detach.
//
//----------------------------------------------------------------------------
#include <dfhead.cxx>
#pragma hdrstop
#include <smalloc.hxx>
#include <dfdeb.hxx>
#ifdef NEWPROPS
#define FULLIMPL
#endif
//
// Take advantage of unique Win95 support of a shared heap.
//
#if defined(_CHICAGO_)
#define HEAP_SHARED 0x04000000 // Secret feature of Win95 only.
//
// Locate the following in a shared data segment.
//
#pragma data_seg(".sdata")
HANDLE gs_hSharedHeap = NULL; // hSharedHeap Handle for Win95.
DFLUID gs_dfluid = LUID_BASE; // shared docfile global LUID
#pragma data_seg()
#define PRINTSTATS
#else // defined(_CHICAGO_)
#ifdef MULTIHEAP
DFLUID gs_dfluid = LUID_BASE; // task memory heap support
INT gs_iSharedHeaps = 0; #endif
#define DLL
#define DEB_STATS 0x00010000
#define DEB_PRINT 0x00020000
#ifdef DLL
#define PERCENT(a,b,c) (int)((((double)a + (double)b) / (double)c) * 100.0)
#define PRINTSTATS \
memDebugOut((DEB_STATS, \ "Total size: %lu, Space: Free: %lu, Alloced: %lu"\ " Blocks: Free: %lu, Alloced: %lu"\ " Efficiency: %.2f%%\n",\ _cbSize,\ GetHeader()->_ulFreeBytes,\ GetHeader()->_ulAllocedBytes,\ GetHeader()->_ulFreeBlocks,\ GetHeader()->GetAllocedBlocks(),\ PERCENT(GetHeader()->_ulFreeBytes,\ GetHeader()->_ulAllocedBytes, _cbSize))); #else
#define PRINTSTATS \
printf( \ "Total size: %lu, Free space: %lu, Alloced space: %lu"\ " Efficiency: %.2f%%\n",\ _cbSize,\ GetHeader()->_ulFreeBytes,\ GetHeader()->_ulAllocedBytes,\ ((double)(GetHeader()->_ulFreeBytes +\ GetHeader()->_ulAllocedBytes) / \ (double)_cbSize) * (double)100); #endif
#if DBG == 1
inline BOOL IsAligned(void *pv) { return !((ULONG_PTR)pv & 7); } #else
#define IsAligned(x) TRUE
#endif
#define SHAREDMEMBASE NULL
#endif // !defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Init, public
//
// Synopsis: Initialize heap for use
//
// Arguments: [pszName] -- Name of shared memory heap to use
//
// Returns: Appropriate status code
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
//
// Remarks: Review the class destructor if you change this code.
//
//----------------------------------------------------------------------------
#if !defined(MULTIHEAP)
SCODE CSmAllocator::Init(LPWSTR pszName) #else
SCODE CSmAllocator::Init(ULONG ulHeapName, BOOL fUnmarshal) #endif
{ SCODE sc = S_OK;
#if !defined(MULTIHEAP)
// Initialize the mutex
sc = _dmtx.Init(TEXT("DocfileAllocatorMutex")); if (FAILED(sc)) { return sc; }
sc = _dmtx.Take(DFM_TIMEOUT); if (FAILED(sc)) { return sc; } #endif
#if defined(_CHICAGO_)
//
// Create a new shared heap if this is the first time thru.
//
if (gs_hSharedHeap == NULL) { gs_hSharedHeap = HeapCreate(HEAP_SHARED, 0, 0); #if DBG == 1
ModifyResLimit(DBRQ_HEAPS, 1); #endif
}
//
// We keep a copy of the shared heap as a flag so the destructor logic
// does the right thing.
//
//
m_hSharedHeap = gs_hSharedHeap;
#else
CSharedMemoryBlock *psmb = NULL; #ifdef MULTIHEAP
_cbSize = 0; if (!fUnmarshal && g_pteb == NtCurrentTeb()) // only for main thread
{ if (g_ulHeapName != 0) // the global shared memory block is active
{ _psmb = &g_smb; // needed for GetHeader
_pbBase = (BYTE *)(_psmb->GetBase()); // needed for GetHeader
if (_pbBase != NULL && GetHeader()->GetAllocedBlocks() == 0) { // its' empty reuse it
psmb = _psmb; _ulHeapName = g_ulHeapName; memDebugOut ((DEB_ITRACE, "Out CSmAllocator::Init " " reuse %x\n", g_ulHeapName)); return sc; } } else { psmb = _psmb = &g_smb; // initialize g_smb
} }
if (psmb == NULL) { psmb = _psmb = new CSharedMemoryBlock (); if (psmb == NULL) return STG_E_INSUFFICIENTMEMORY; }
WCHAR pszName[DOCFILE_SM_NAMELEN]; wsprintf(pszName, L"DfSharedHeap%X", ulHeapName); #else
psmb = &_smb; #endif
#if WIN32 == 100 || WIN32 > 200
CGlobalSecurity gs; if (SUCCEEDED(sc = gs.Init(TRUE))) { #else
LPSECURITY_ATTRIBUTES gs = NULL; #endif
// the SMB needs a few bytes for its own header. If we request
// a page sized allocation, those few header bytes will cause an
// extra page to be allocated, so to prevent that we subtract off
// the header space from our requests.
sc = psmb->Init(pszName, DOCFILE_SM_SIZE - psmb->GetHdrSize(), // reserve size
INITIALHEAPSIZE - psmb->GetHdrSize(), // commit size
SHAREDMEMBASE, // base address
(SECURITY_DESCRIPTOR *)gs, // security descriptor
TRUE); // create if doesn't exist
// Always pass in TRUE for "fOKToCreate", since passing FALSE
// will open an existing mapping in read-only mode, but we need read-write
#if WIN32 == 100 || WIN32 > 200
} #endif
if (SUCCEEDED(sc)) { #if DBG == 1
ModifyResLimit(DBRQ_HEAPS, 1); #endif
_cbSize = psmb->GetSize(); _pbBase = (BYTE *)(psmb->GetBase()); #ifdef MULTIHEAP
gs_iSharedHeaps++; _ulHeapName = ulHeapName; #endif
if (psmb->Created()) { if (fUnmarshal) // do not allow creates for unmarshals
{ Uninit(); memErr (EH_Err, STG_E_INVALIDFUNCTION); } else { Reset(); } } #ifdef MULTIHEAP
if (psmb == &g_smb) g_ulHeapName = ulHeapName; // store global heap name
#endif
PRINTSTATS; } #endif
#if defined(MULTIHEAP)
memDebugOut ((DEB_ITRACE, "Out CSmAllocator::Init sc=%x %x\n", sc, ulHeapName)); #else
_dmtx.Release(); memDebugOut ((DEB_ITRACE, "Out CSmAllocator::Init sc=%x\n", sc)); #endif
EH_Err: return sc; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::QueryInterface, public
//
// Synopsis: Standard QI
//
// Arguments: [iid] - Interface ID
// [ppvObj] - Object return
//
// Returns: Appropriate status code
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CSmAllocator::QueryInterface(REFIID iid, void **ppvObj) { SCODE sc = S_OK; memDebugOut((DEB_ITRACE, "In CSmAllocator::QueryInterface:%p()\n", this));
if (IsEqualIID(iid, IID_IMalloc) || IsEqualIID(iid, IID_IUnknown)) { *ppvObj = (IMalloc *) this; CSmAllocator::AddRef(); } else sc = E_NOINTERFACE; memDebugOut((DEB_ITRACE, "Out CSmAllocator::QueryInterface\n"));
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::AddRef, public
//
// Synopsis: Add reference
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSmAllocator::AddRef(void) { #ifdef MULTIHEAP
return ++_cRefs; #else
return 1; #endif
}
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Release, public
//
// Synopsis: Release
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CSmAllocator::Release(void) { #ifdef MULTIHEAP
ULONG cRefs = --_cRefs; if (cRefs <= 0 && this != &g_ErrorSmAllocator) delete this; return cRefs; #else
return 0; #endif
}
#if !defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::FindBlock, private
//
// Synopsis: Find an appropriately sized block in the heap.
//
// Arguments: [cb] -- Size of block required
//
// Returns: Pointer to block, NULL on failure
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
CBlockHeader * CSmAllocator::FindBlock(SIZE_T cb, CBlockHeader **ppbhPrev) { CBlockHeader *pbhCurrent = GetAddress(GetHeader()->GetFirstFree()); *ppbhPrev = NULL; while (pbhCurrent != NULL) { memAssert(IsAligned(pbhCurrent)); if ((pbhCurrent->GetSize() >= cb) && (pbhCurrent->IsFree())) { memAssert(pbhCurrent->GetSize() < _cbSize); //MULTIHEAP
memAssert((BYTE *)pbhCurrent >= _pbBase && (BYTE *)pbhCurrent < _pbBase + _cbSize); // MULTIHEAP
break; } else { memAssert (pbhCurrent->GetNext() <= _cbSize); // MULITHEAP
*ppbhPrev = pbhCurrent; pbhCurrent = GetAddress(pbhCurrent->GetNext()); } } return pbhCurrent; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Reset, private
//
// Synopsis: Reset the heap to its original empty state.
//
// Returns: Appropriate status code
//
// History: 04-Apr-94 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline SCODE CSmAllocator::Reset(void) { memDebugOut((DEB_ITRACE, "In CSmAllocator::Reset:%p()\n", this));
CBlockHeader *pbh = (CBlockHeader *) (_pbBase + sizeof(CHeapHeader)); memAssert(IsAligned(pbh)); pbh->SetFree(); pbh->SetSize(_cbSize - sizeof(CHeapHeader)); pbh->SetNext(0);
memAssert((BYTE *)pbh + pbh->GetSize() == _pbBase + _cbSize); GetHeader()->SetFirstFree(GetOffset(pbh)); GetHeader()->SetCompacted(); GetHeader()->ResetAllocedBlocks(); GetHeader()->ResetLuid();
#if DBG == 1
GetHeader()->_ulAllocedBytes = 0; GetHeader()->_ulFreeBytes = pbh->GetSize() - sizeof(CBlockPreHeader); GetHeader()->_ulFreeBlocks = 1; #endif
memDebugOut((DEB_ITRACE, "Out CSmAllocator::Reset\n"));
return S_OK; }
#endif // !defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Alloc, public
//
// Synopsis: Allocate memory
//
// Arguments: [cb] -- Number of bytes to allocate
//
// Returns: Pointer to block, NULL if failure
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(void *) CSmAllocator::Alloc ( SIZE_T cb ) { void *pv = NULL; #if DBG == 1
SIZE_T cbSize = cb; #endif
#if !defined(_CHICAGO_)
CBlockHeader *pbh = NULL; CBlockHeader *pbhPrev = NULL; SCODE sc; #endif
memDebugOut((DEB_ITRACE, "In CSmAllocator::Alloc:%p(%lu)\n", this, cb));
#if defined(_CHICAGO_)
pv = HeapAlloc(m_hSharedHeap, 0, cb);
#else // !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
CLockDfMutex lckdmtx(_dmtx); #endif
#ifdef MULTIHEAP
if (_pbBase == NULL) { memAssert (g_pTaskAllocator != NULL); return g_pTaskAllocator->Alloc (cb); } #endif
Sync();
//The block must be at least large enough to hold the standard
// header (size and free bit) and a pointer to the next block.
if (cb < sizeof(CBlockHeader) - sizeof(CBlockPreHeader)) { cb = sizeof(CBlockHeader) - sizeof(CBlockPreHeader); } cb = cb + sizeof(CBlockPreHeader);
//Make cb 8 byte aligned.
if (cb & 7) { cb += (8 - (cb & 7)); }
memAssert((cb >= CBLOCKMIN) && "Undersized block requested."); pbh = FindBlock(cb, &pbhPrev);
if (pbh == NULL) { if (!(GetHeader()->IsCompacted())) { //Do a heap merge and try to allocate again.
CSmAllocator::HeapMinimize(); pbh = FindBlock(cb, &pbhPrev); } if (pbh == NULL) { #ifdef MULTIHEAP
CSharedMemoryBlock *psmb = _psmb; #else
CSharedMemoryBlock *psmb = &_smb; #endif
#if DBG == 1
ULONG ulOldSize = psmb->GetSize(); #endif
sc = (ULONG)psmb->Commit(_cbSize + (ULONG)max(cb, MINHEAPGROWTH)); if (SUCCEEDED(sc)) { //Attach newly committed space to free list.
CBlockHeader *pbhNew = (CBlockHeader *) (_pbBase + _cbSize);
_cbSize = psmb->GetSize();
memAssert((pbhPrev == NULL) || (pbhPrev->GetNext() == 0)); memAssert(_cbSize > ulOldSize);
if (pbhPrev != NULL) { pbhPrev->SetNext(GetOffset(pbhNew)); } else { GetHeader()->SetFirstFree(GetOffset(pbhNew)); }
pbhNew->SetNext(0); pbhNew->SetSize(max(cb, MINHEAPGROWTH)); pbhNew->SetFree();
memAssert((BYTE *)pbhNew + pbhNew->GetSize() == _pbBase + _cbSize); #if DBG == 1
GetHeader()->_ulFreeBytes += pbhNew->GetSize() - sizeof(CBlockPreHeader); GetHeader()->_ulFreeBlocks += 1; #endif
pbh = pbhNew; } #if DBG == 1
else { memDebugOut((DEB_ERROR, "Can't grow shared memory\n")); PrintAllocatedBlocks(); } #endif
} }
if (pbh != NULL) { //Allocate the found block.
if ((pbh->GetSize() > cb) && (pbh->GetSize() - cb > CBLOCKMIN)) { //Split an existing block. No free list update required.
CBlockHeader *pbhNew = (CBlockHeader *)((BYTE *)pbh + (pbh->GetSize() - cb));
pbhNew->SetSize(cb); pbhNew->ResetFree(); pbhNew->SetNext(0); pbh->SetSize(pbh->GetSize() - cb); #if DBG == 1
cbSize = cb; GetHeader()->_ulAllocedBytes += (cb - sizeof(CBlockPreHeader)); //The number of available free bytes decreases by the number
// of bytes allocated
GetHeader()->_ulFreeBytes -= cb; #endif
memAssert(IsAligned(pbhNew)); memAssert(IsAligned(pbh)); pbh = pbhNew; } else { //Use an entire block. Update free list appropriately.
memAssert(IsAligned(pbh)); pbh->ResetFree(); if (pbhPrev != NULL) { pbhPrev->SetNext(pbh->GetNext()); } else { GetHeader()->SetFirstFree(pbh->GetNext()); } #if DBG == 1
cbSize = pbh->GetSize() - sizeof(CBlockPreHeader); GetHeader()->_ulAllocedBytes += cbSize; GetHeader()->_ulFreeBytes -= cbSize; GetHeader()->_ulFreeBlocks--; #endif
pbh->SetNext(0); } }
if (pbh != NULL) { pv = (BYTE *)pbh + sizeof(CBlockPreHeader); GetHeader()->IncrementAllocedBlocks(); } #endif // !defined(_CHICAGO_)
memDebugOut((DEB_ITRACE, "Out CSmAllocator::Alloc=> %p\n", pv));
#if !defined(_CHICAGO_)
memAssert(IsAligned(pv)); #endif // !defined(_CHICAGO_)
PRINTSTATS; #if DBG == 1
if (pv == NULL) { #if defined(_CHICAGO_)
memDebugOut((DEB_ERROR, "Failed allocation of %lu bytes.\n", cb)); #else // !defined(_CHICAGO_)
memDebugOut((DEB_ERROR, "Failed allocation of %lu bytes. Heap size is %lu\n", cb, _cbSize)); #endif // !defined(_CHICAGO_)
} else { //Allocated some bytes. Record this for leak tracking.
ModifyResLimit(DBRQ_MEMORY_ALLOCATED, (LONG)pbh->GetSize()); } #endif
return pv; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Realloc, public
//
// Synopsis: Resize the block given
//
// Arguments: [pv] -- Pointer to block to realloc
// [cb] -- New size for block
//
// Returns: Pointer to new block, NULL if failure
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(void *) CSmAllocator::Realloc( void *pv, SIZE_T cb ) { void *pvNew = NULL; #ifdef FULLIMPL
memDebugOut((DEB_ITRACE, "In CSmAllocator::Realloc:%p()\n", this));
#if defined(_CHICAGO_)
pvNew = HeapReAlloc(m_hSharedHeap, 0, pv, cb);
#else
#if !defined(MULTIHEAP)
CLockDfMutex lckdmtx(_dmtx); #endif
#ifdef MULTIHEAP
if (_pbBase == NULL) { memAssert (g_pTaskAllocator != NULL); return g_pTaskAllocator->Realloc (pv, cb); } #endif
if ((pv != NULL) && (cb == 0)) { CSmAllocator::Free(pv); return NULL; }
pvNew = CSmAllocator::Alloc(cb); if (pvNew != NULL && pv != NULL) { //Copy contents
memcpy(pvNew, pv, min(cb, CSmAllocator::GetSize(pv))); CSmAllocator::Free(pv); } #endif
memDebugOut((DEB_ITRACE, "Out CSmAllocator::Realloc\n")); #endif
PRINTSTATS; return pvNew; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::DoFree, private
//
// Synopsis: Free a memory block
//
// Arguments: [pv] -- Pointer to block to free
//
// Returns: void
//
// History: 26-Jul-95 SusiA Created
//
//----------------------------------------------------------------------------
inline void CSmAllocator::DoFree(void *pv) { #ifdef MULTIHEAP
if (_pbBase == NULL) { memAssert (g_pTaskAllocator != NULL); g_pTaskAllocator->Free (pv); return; } #endif
memDebugOut((DEB_ITRACE, "In CSmAllocator::DoFree:%p(%p)\n", this, pv)); #if DBG == 1
SSIZE_T cbSize = 0; #endif
#if defined(_CHICAGO_)
if (pv != NULL) { #if DBG == 1
cbSize = HeapSize(m_hSharedHeap, 0, pv); #endif
HeapFree(m_hSharedHeap, 0, pv); }
#else
Sync(); if (pv != NULL) { CBlockHeader *pbh = (CBlockHeader *) ((BYTE *)pv - sizeof(CBlockPreHeader)); #ifdef MULTIHEAP
SIZE_T ulSize = pbh->GetSize(); // temporary to hold size for debug
#if DBG == 1
cbSize = ulSize; #endif
#endif
memAssert(IsAligned(pbh)); memAssert((BYTE*)pbh >= _pbBase && (BYTE*)pbh < _pbBase + _cbSize); // MULTIHEAP
pbh->SetFree(); pbh->SetNext(GetHeader()->GetFirstFree());
GetHeader()->SetFirstFree(GetOffset(pbh)); GetHeader()->ResetCompacted(); if (GetHeader()->DecrementAllocedBlocks() == 0) { #ifdef MULTIHEAP
Uninit(); #else
Reset(); #endif
} #if DBG == 1
else { GetHeader()->_ulAllocedBytes -= (pbh->GetSize() - sizeof(CBlockPreHeader)); memAssert (GetHeader()->_ulAllocedBytes <= _cbSize); GetHeader()->_ulFreeBytes += (pbh->GetSize() - sizeof(CBlockPreHeader)); GetHeader()->_ulFreeBlocks++; } #endif
#ifdef MULTIHEAP
memDebugOut((DEB_ITRACE, "Out CSmAllocator::DoFree. Freed %lu\n", ulSize)); // don't access shared memory
#else
memDebugOut((DEB_ITRACE, "Out CSmAllocator::DoFree. Freed %lu\n", pbh->GetSize())); #endif
} #endif
#if !defined(MULTIHEAP)
// the shared heap may have been unmapped, mustn't read it now
PRINTSTATS; #endif
#if DBG == 1
//Freed some bytes, so record that.
ModifyResLimit(DBRQ_MEMORY_ALLOCATED, (LONG)-cbSize); #endif
} //+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Free, public
//
// Synopsis: Free a memory block
//
// Arguments: [pv] -- Pointer to block to free
//
// Returns: void
//
// History: 29-Mar-94 PhilipLa Created
// 26-Jul-95 SusiA Moved bulk of work to DoFree to
// share code between Free and
// FreeNoMutex
//
//----------------------------------------------------------------------------
STDMETHODIMP_(void) CSmAllocator::Free(void *pv) { memDebugOut((DEB_ITRACE, "In CSmAllocator::Free:%p(%p)\n", this, pv)); #if !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
CLockDfMutex lckdmtx(_dmtx); #endif
#endif
DoFree(pv);
} //+---------------------------------------------------------------------------
//
// Member: CSmAllocator::FreeNoMutex, public
//
// Synopsis: Free a memory block without first aquiring the mutex.
// This function is equivalent to Free above, except that is does
// not attempt to first aquire the mutex. It should be used OLNY
// when the calling function guarantees to already have the mutex.
//
//
// Arguments: [pv] -- Pointer to block to free
//
// Returns: void
//
// History: 19-Jul-95 SusiA Created
//
//----------------------------------------------------------------------------
void CSmAllocator::FreeNoMutex(void *pv) { memDebugOut((DEB_ITRACE, "In CSmAllocator::FreeNoMutex:%p(%p)\n", this, pv)); #if !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
//ensure we already have the mutex
memAssert(_dmtx.HaveMutex()); #endif
#endif
DoFree(pv);
}
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetSize, public
//
// Synopsis: Return the size of the given block
//
// Arguments: [pv] -- Block to get size of
//
// Returns: Size of block pointer to by pv
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(SIZE_T) CSmAllocator::GetSize(void * pv) { #if !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
CLockDfMutex lckdmtx(_dmtx); #endif
#endif
#ifdef MULTIHEAP
if (_pbBase == NULL) { memAssert (g_pTaskAllocator != NULL); return g_pTaskAllocator->GetSize (pv); } #endif
Sync(); SIZE_T ulSize = (SIZE_T)-1; #ifdef FULLIMPL
memDebugOut((DEB_ITRACE, "In CSmAllocator::GetSize:%p()\n", this)); if (pv != NULL) { #if defined(_CHICAGO_)
ulSize = HeapSize(m_hSharedHeap, 0, pv); #else
CBlockHeader *pbh; pbh = (CBlockHeader *)((BYTE *)pv - sizeof(CBlockPreHeader)); ulSize = pbh->GetSize() - sizeof(CBlockPreHeader); #endif
} memDebugOut((DEB_ITRACE, "Out CSmAllocator::GetSize\n")); #endif
return ulSize; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::DidAlloc, public
//
// Synopsis: Return '1' if this heap allocated pointer at pv
//
// Arguments: [pv] -- Pointer to block
//
// Returns: '1' == This heap allocated block.
// '0' == This heap did not allocate block.
// '-1' == Could not determine if this heap allocated block.
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(int) CSmAllocator::DidAlloc(void FAR * pv) { #ifdef MULTIHEAP
if (_pbBase == NULL) { memAssert (g_pTaskAllocator != NULL); return g_pTaskAllocator->DidAlloc (pv); } #endif
int i = -1; #ifdef FULLIMPL
memDebugOut((DEB_ITRACE, "In CSmAllocator::DidAlloc:%p()\n", this)); #if defined(_CHICAGO_)
if (HeapValidate(m_hSharedHeap, 0, pv)) { i = 1; } else { i = 0; } #else // !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
CLockDfMutex lckdmtx(_dmtx); #endif
i = ((BYTE *)pv >= _pbBase) && ((BYTE *)pv <= (_pbBase + _cbSize)); #endif // !defined(_CHICAGO_)
memDebugOut((DEB_ITRACE, "Out CSmAllocator::DidAlloc\n")); #endif
return i; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::HeapMinimize, public
//
// Synopsis: Minimize the heap
//
// Arguments: None.
//
// Returns: void.
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(void) CSmAllocator::HeapMinimize(void) { #if !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
CLockDfMutex lckdmtx(_dmtx); #endif
#endif
#ifdef MULTIHEAP
if (_pbBase == NULL) { memAssert (g_pTaskAllocator != NULL); g_pTaskAllocator->HeapMinimize (); return; } #endif
memDebugOut((DEB_ITRACE, "In CSmAllocator::HeapMinimize:%p()\n", this));
PRINTSTATS; #if defined(_CHICAGO_)
HeapCompact(m_hSharedHeap, 0);
#else // !defined(_CHICAGO_)
CBlockHeader *pbhCurrent; CBlockHeader *pbhLast = NULL; BYTE *pbEnd = _pbBase + _cbSize;
#if DBG == 1
PrintFreeBlocks(); GetHeader()->_ulAllocedBytes = 0; GetHeader()->_ulFreeBytes = 0; GetHeader()->_ulFreeBlocks = 0; #endif
pbhCurrent = (CBlockHeader *)(_pbBase + sizeof(CHeapHeader));
while ((BYTE *)pbhCurrent < pbEnd) { memAssert(IsAligned(pbhCurrent)); memAssert((pbhCurrent->GetSize() != 0) && "Zero size block found."); if (pbhCurrent->IsFree()) { //Check last block. If adjacent, merge them. If not,
// update pbhNext.
if (pbhLast == NULL) { GetHeader()->SetFirstFree(GetOffset(pbhCurrent)); #if DBG == 1
GetHeader()->_ulFreeBlocks = 1; #endif
} else { if (pbhLast->GetSize() + GetOffset(pbhLast) == GetOffset(pbhCurrent)) { //Merge the blocks.
pbhLast->SetSize(pbhLast->GetSize() + pbhCurrent->GetSize()); pbhCurrent = pbhLast; } else { #if DBG == 1
GetHeader()->_ulFreeBytes += (pbhLast->GetSize() - sizeof(CBlockPreHeader)); GetHeader()->_ulFreeBlocks++; #endif
pbhLast->SetNext(GetOffset(pbhCurrent)); } } pbhLast = pbhCurrent; } #if DBG == 1
else { GetHeader()->_ulAllocedBytes += (pbhCurrent->GetSize() - sizeof(CBlockPreHeader)); } #endif
//Move to next block.
pbhCurrent = (CBlockHeader *)((BYTE *)pbhCurrent + pbhCurrent->GetSize()); }
if (pbhLast != NULL) { #if DBG == 1
GetHeader()->_ulFreeBytes += (pbhLast->GetSize() - sizeof(CBlockPreHeader)); #endif
pbhLast->SetNext(0); } else { GetHeader()->SetFirstFree(0); }
GetHeader()->SetCompacted(); #if DBG == 1
PrintFreeBlocks(); #endif
#endif // !defined(_CHICAGO_)
memDebugOut((DEB_ITRACE, "Out CSmAllocator::HeapMinimize\n")); PRINTSTATS; }
#if !defined(_CHICAGO_)
#if DBG == 1
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::PrintFreeBlocks, private
//
// Synopsis: Debug code to print sizes of free blocks
//
// History: 25-Apr-94 PhilipLa Created
//
//----------------------------------------------------------------------------
void CSmAllocator::PrintFreeBlocks(void) { CBlockHeader *pbhCurrent = GetAddress(GetHeader()->GetFirstFree());
memDebugOut((DEB_PRINT, "There are %lu total free blocks\n", GetHeader()->_ulFreeBlocks)); while (pbhCurrent != NULL) { memDebugOut((DEB_PRINT, "Free block %p has size %lu\n", pbhCurrent, pbhCurrent->GetSize())); pbhCurrent = GetAddress(pbhCurrent->GetNext()); } } #endif
#ifdef MULTIHEAP
#if DBG == 1
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::PrintAllocatedBlocks, private
//
// Synopsis: Debug code to find allocated block(s) that leaked
//
// History: 25-Nov-95 HenryLee Created
//
//----------------------------------------------------------------------------
void CSmAllocator::PrintAllocatedBlocks(void) { CBlockHeader *pbhCurrent; CBlockHeader *pbhLast = NULL; BYTE *pbEnd = _pbBase + _cbSize; ULONG *pul;
if (_psmb != NULL) { pbhCurrent = (CBlockHeader *)(_pbBase + sizeof(CHeapHeader));
while ((BYTE *)pbhCurrent < pbEnd) { memAssert(IsAligned(pbhCurrent)); memAssert((pbhCurrent->GetSize() != 0) && "Zero size block found."); if (!pbhCurrent->IsFree()) { pul = (ULONG *)((BYTE *)pbhCurrent + sizeof(CBlockPreHeader)); memDebugOut((DEB_ERROR, "Allocated Block %p %8x %8x (size %lu)\n", pul, *pul, *(pul+1), pbhCurrent->GetSize())); } else { pul = (ULONG *)pbhCurrent; memDebugOut((DEB_ERROR, "Free Block %p %8x %8x (size %lu)\n", pul, *pul, *(pul+1), pbhCurrent->GetSize())); } pbhCurrent = (CBlockHeader *)((BYTE *)pbhCurrent + pbhCurrent->GetSize()); } } } #endif // DBG == 1
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::SetState
//
// Synopsis: replace thread local state by PerContext state
//
// History: 20-Nov-95 Henrylee Created
//
//----------------------------------------------------------------------------
void CSmAllocator::SetState (CSharedMemoryBlock *psmb, BYTE * pbBase, ULONG ulHeapName, CPerContext ** ppcPrev, CPerContext *ppcOwner) { memDebugOut((DEB_ITRACE, "In CSmAllocator::SetState(%p, %p, %lx, %p, %p, %p) (this == %p)\n", psmb, pbBase, ulHeapName, ppcPrev, ppcOwner, _ppcOwner, this));
_psmb = psmb; _pbBase = pbBase; _cbSize = (_psmb) ? _psmb->GetSize() : 0; _ulHeapName = ulHeapName; DFBASEPTR = _pbBase;
if (ppcPrev != NULL) *ppcPrev = _ppcOwner; _ppcOwner = ppcOwner;
// memAssert (g_smAllocator.GetBase() == DFBASEPTR);
memDebugOut((DEB_ITRACE, "Out CSmAllocator::SetState()\n")); }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetState
//
// Synopsis: retrive thread local allocator state into percontext
//
// History: 20-Nov-95 Henrylee Created
//
//----------------------------------------------------------------------------
void CSmAllocator::GetState (CSharedMemoryBlock **ppsmb, BYTE ** ppbBase, ULONG *pulHeapName) { *ppsmb = _psmb; *ppbBase = _pbBase; *pulHeapName = _ulHeapName; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Uninit
//
// Synopsis: unmap the shared memory region
//
// History: 20-Nov-95 Henrylee Created
//
//----------------------------------------------------------------------------
SCODE CSmAllocator::Uninit () { memDebugOut((DEB_ITRACE, "In CSmAllocator::Uninit\n")); if (_psmb != NULL) { if (_psmb != &g_smb) { // This is last block in the heap, so we can close the heap
// now. There must be no shared heap accesses after this.
delete _psmb; #if DBG == 1
ModifyResLimit(DBRQ_HEAPS, -1); #endif
gs_iSharedHeaps--; } else { if (GetHeader()->GetAllocedBlocks() == 0) Reset(); // for g_smb
} _psmb = NULL; } _pbBase = NULL; memDebugOut((DEB_ITRACE, "Out CSmAllocator::Uninit %x\n", _ulHeapName));
_ulHeapName = 0;
return S_OK; }
#endif // MULTIHEAP
#endif // !defined(_CHICAGO_)
|