|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1994.
//
// File: heap.hxx
//
// Contents: Heap code headers
//
// Classes: CHeap
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
// 10-Apr095 HenryLee Added global LUID
// 10-May-95 KentCe Defer Heap Destruction to the last
// process detach.
//
//----------------------------------------------------------------------------
#ifndef __HEAP_HXX__
#define __HEAP_HXX__
#include <smblock.hxx>
#include <memdebug.hxx>
#include <msf.hxx>
#include <df32.hxx>
//Space to reserve for heap.
const ULONG MINHEAPGROWTH = 4096; const ULONG INITIALHEAPSIZE = 16384;
#ifdef MULTIHEAP
#include <ntpsapi.h>
class CPerContext;
#endif
//+-------------------------------------------------------------------------
//
// Class: CLockDfMutex
//
// Purpose: Simple class to guarantee that a DfMutex is unlocked
//
// History: 29-Apr-95 DonnaLi Created
//
//--------------------------------------------------------------------------
class CLockDfMutex { public:
CLockDfMutex(CDfMutex& dmtx);
~CLockDfMutex(void);
private:
CDfMutex& _dmtx; };
//+-------------------------------------------------------------------------
//
// Member: CLockDfMutex::CLockDfMutex
//
// Synopsis: Get mutex
//
// Arguments: [dmtx] -- mutex to get
//
// History: 29-Apr-95 DonnaLi Created
//
//--------------------------------------------------------------------------
inline CLockDfMutex::CLockDfMutex(CDfMutex& dmtx) : _dmtx(dmtx) { _dmtx.Take(DFM_TIMEOUT); }
//+-------------------------------------------------------------------------
//
// Member: CLockDfMutex::~CLockDfMutex
//
// Synopsis: Release the mutex
//
// History: 29-Apr-95 DonnaLi Created
//
//--------------------------------------------------------------------------
inline CLockDfMutex::~CLockDfMutex(void) { _dmtx.Release(); }
//
// Take advantage of Windows 95 Shared Heap.
//
#if !defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Class: CBlockPreHeader
//
// Purpose: Required header fields for a block
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
class CBlockPreHeader { protected: SIZE_T _ulSize; //Size of block
BOOL _fFree; //TRUE if block is free
};
//+---------------------------------------------------------------------------
//
// Class: CBlockHeader
//
// Purpose: Fields required for free blocks but overwritten for
// allocated blocks.
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
class CBlockHeader: public CBlockPreHeader { public: inline SIZE_T GetSize(void) const; inline BOOL IsFree(void) const; inline SIZE_T GetNext(void) const;
inline void SetSize(SIZE_T ulSize); inline void SetFree(void); inline void ResetFree(void); inline void SetNext(SIZE_T ulNext); private: SIZE_T _ulNext; //Pointer to next block
};
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::GetSize, public
//
// Synopsis: Returns the size of the block
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline SIZE_T CBlockHeader::GetSize(void) const { return _ulSize; }
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::IsFree, public
//
// Synopsis: Returns free state of block
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline BOOL CBlockHeader::IsFree(void) const { memAssert (_fFree == TRUE || _fFree == FALSE); // check for corruption
return _fFree; }
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::GetNext, public
//
// Synopsis: Return next offset
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline SIZE_T CBlockHeader::GetNext(void) const { return _ulNext; }
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::SetSize, public
//
// Synopsis: Set size of block
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CBlockHeader::SetSize(SIZE_T ulSize) { _ulSize = ulSize; }
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::SetFree, public
//
// Synopsis: Set this block to free
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CBlockHeader::SetFree(void) { _fFree = TRUE; }
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::ResetFree, public
//
// Synopsis: Set this block to !free
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CBlockHeader::ResetFree(void) { _fFree = FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CBlockHeader::SetNext, public
//
// Synopsis: Set next offset
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CBlockHeader::SetNext(SIZE_T ulNext) { _ulNext = ulNext; }
const ULONG CBLOCKMIN = ((sizeof(CBlockHeader) & 7) ? sizeof(CBlockHeader) + (8 - (sizeof(CBlockHeader) & 7)) : sizeof(CBlockHeader));
//+---------------------------------------------------------------------------
//
// Class: CHeapHeader
//
// Purpose: Header information for shared memory heap
//
// Interface:
//
// History: 30-Mar-94 PhilipLa Created
//
// Notes: The size of this structure must be a multiple of 8 bytes.
//
//----------------------------------------------------------------------------
class CHeapHeader { public: inline SIZE_T GetFirstFree(void) const; inline void SetFirstFree(SIZE_T ulNew);
inline BOOL IsCompacted(void) const; inline void SetCompacted(void); inline void ResetCompacted(void);
inline void ResetAllocedBlocks(void); inline SIZE_T IncrementAllocedBlocks(void); inline SIZE_T DecrementAllocedBlocks(void);
inline SIZE_T GetAllocedBlocks(void); inline DFLUID IncrementLuid(void); inline void ResetLuid(void);
#if DBG == 1
SIZE_T _ulAllocedBytes; SIZE_T _ulFreeBytes; SIZE_T _ulFreeBlocks; #endif
private: SIZE_T _ulFirstFree; SIZE_T _ulAllocedBlocks; BOOL _fIsCompacted; DFLUID _dfLuid; #if DBG == 1
SIZE_T ulPad; #endif
};
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::GetFirstFree, public
//
// Synopsis: Return first free information
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline SIZE_T CHeapHeader::GetFirstFree(void) const { return _ulFirstFree; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::SetFirstFree, public
//
// Synopsis: Set first free information
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CHeapHeader::SetFirstFree(SIZE_T ulNew) { _ulFirstFree = ulNew; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::IsCompacted, public
//
// Synopsis: Return TRUE if heap is compacted
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline BOOL CHeapHeader::IsCompacted(void) const { return _fIsCompacted; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::SetCompacted, public
//
// Synopsis: Set compacted bit
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CHeapHeader::SetCompacted(void) { _fIsCompacted = TRUE; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::ResetCompacted, public
//
// Synopsis: Reset compacted bit
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CHeapHeader::ResetCompacted(void) { _fIsCompacted = FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::IncrementLuid, public
//
// Synopsis: Increment the global LUID
//
// History: 06-Apr-95 HenryLee Created
//
//----------------------------------------------------------------------------
inline ULONG CHeapHeader::IncrementLuid() { return ++_dfLuid; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::ResetLuid, public
//
// Synopsis: Increment the global LUID
//
// History: 06-Apr-95 HenryLee Created
//
//----------------------------------------------------------------------------
inline void CHeapHeader::ResetLuid() { _dfLuid = LUID_BASE; // some LUIDs are reserved
}
#ifdef MULTIHEAP
extern DFLUID gs_dfluid; // task memory support
extern INT gs_iSharedHeaps; // number ofshared heaps
#endif
#else // define(_CHICAGO_)
extern HANDLE gs_hSharedHeap; // hSharedHeap Handle for Win95.
extern DFLUID gs_dfluid; // shared docfile LUID
#endif // !define(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Class: CSmAllocator
//
// Purpose: Shared memory heap implementation
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
//
//----------------------------------------------------------------------------
class CSmAllocator: public IMalloc { public: inline CSmAllocator(); inline ~CSmAllocator();
STDMETHOD_(ULONG,AddRef) ( void ); STDMETHOD_(ULONG,Release) ( void ); STDMETHOD(QueryInterface) ( REFIID riid, void ** ppv ); STDMETHOD_(void*,Alloc) ( SIZE_T cb ); STDMETHOD_(void *,Realloc) ( void *pvCurrent, SIZE_T cbNeeded ); STDMETHOD_(void,Free) ( void *pvMemToFree ); STDMETHOD_(SIZE_T,GetSize) ( void * pv ); STDMETHOD_(void,HeapMinimize) ( void ); STDMETHOD_(int,DidAlloc) ( void * pv );
inline SCODE Sync(void); inline DFLUID IncrementLuid(void);
#if !defined(MULTIHEAP)
SCODE Init ( LPWSTR pszName ); #else
SCODE Init ( ULONG ulHeapName, BOOL fUnmarshal ); #endif
inline void * GetBase(void); // This function is equivalent to Free above, except that is does
// not attempt to first acquire the mutex. It should be used ONLY
// when the calling function guarantees to already have the mutex.
void FreeNoMutex (void * pv); #if !defined(MULTIHEAP)
inline CDfMutex * GetMutex (void); #endif
#ifdef MULTIHEAP
void SetState (CSharedMemoryBlock *psmb, BYTE * pbBase, ULONG ulHeapName, CPerContext ** ppcPrev, CPerContext *ppcOwner); void GetState (CSharedMemoryBlock **ppsmb, BYTE ** ppbBase, ULONG *pulHeapName); inline const ULONG GetHeapName (); SCODE Uninit (); inline const ULONG GetHeapSize () { return _cbSize; }; #if DBG == 1
void PrintAllocatedBlocks(void); #endif
#endif
private: inline void DoFree (void *pv); #if !defined(MULTIHEAP)
CDfMutex _dmtx; #endif
//
// Take advantage of Windows 95 Shared Heap.
//
#if !defined(_CHICAGO_)
CBlockHeader * FindBlock(SIZE_T cb, CBlockHeader **ppbhPrev); inline CHeapHeader *GetHeader(void); inline CBlockHeader * GetAddress(SIZE_T ulOffset) const; inline ULONG GetOffset(CBlockHeader *pbh) const;
inline SCODE Reset(void); #if DBG == 1
void PrintFreeBlocks(void); #endif
#ifdef MULTIHEAP
CSharedMemoryBlock *_psmb; BYTE *_pbBase; ULONG _cbSize; CPerContext * _ppcOwner; ULONG _ulHeapName; ULONG _cRefs; // yes, this object has a lifetime now
#else
CSharedMemoryBlock _smb;
BYTE *_pbBase; SIZE_T _cbSize; #endif // MULTIHEAP
#else // defined(_CHICAGO_)
HANDLE m_hSharedHeap;
#endif // !defined(_CHICAGO_)
};
#ifdef MULTIHEAP
extern CSmAllocator g_SmAllocator; // single-threaded allocator
extern CSharedMemoryBlock g_smb; //performance optimization
extern ULONG g_ulHeapName; extern CSmAllocator& GetTlsSmAllocator(); // all other threads
extern TEB * g_pteb; #define g_smAllocator (GetTlsSmAllocator())
//+---------------------------------------------------------------------------
//
// Class: CErrorSmAllocator
//
// Synopsis: returned by GetTlsSmAllocator for out of memory failures
//
// History: 02-May-1996 HenryLee Created
//
//----------------------------------------------------------------------------
class CErrorSmAllocator : public CSmAllocator { public: STDMETHOD_(void*,Alloc) (SIZE_T cb) { return NULL; }; STDMETHOD_(void*,Realloc) (void* pv, SIZE_T cb) { return NULL; }; STDMETHOD_(void,Free) (void *pv) { return; }; STDMETHOD_(SIZE_T,GetSize) (void *pv) { return 0; }; STDMETHOD_(void,HeapMinimize) () { return; }; STDMETHOD_(int,DidAlloc) (void *pv) { return FALSE; }; SCODE Init (ULONG ul, BOOL f) { return STG_E_INSUFFICIENTMEMORY; }; SCODE Sync (void) { return STG_E_INSUFFICIENTMEMORY; }; }; extern CErrorSmAllocator g_ErrorSmAllocator; extern IMalloc * g_pTaskAllocator;
#else
extern CSmAllocator g_smAllocator; #endif
extern CRITICAL_SECTION g_csScratchBuffer;
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::CSmAllocator, public
//
// Synopsis: Constructor
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
//
//----------------------------------------------------------------------------
inline CSmAllocator::CSmAllocator(void) #if !defined(_CHICAGO_)
#ifdef MULTIHEAP
: _cbSize(0), _pbBase(NULL), _cRefs(1), _ulHeapName(0), _psmb(NULL), _ppcOwner(NULL) #else
: _cbSize(0) #endif // MULTIHEAP
#else
: m_hSharedHeap(NULL) #endif
{ #if !defined(MULTIHEAP)
InitializeCriticalSection(&g_csScratchBuffer); #ifdef COORD
InitializeCriticalSection(&g_csResourceList); #endif
#endif // MULTIHEAP
}
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::~CSmAllocator, public
//
// Synopsis: Destructor
//
// 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.
//
//----------------------------------------------------------------------------
inline CSmAllocator::~CSmAllocator(void) { #if !defined(MULTIHEAP)
DeleteCriticalSection(&g_csScratchBuffer); #ifdef COORD
DeleteCriticalSection(&g_csResourceList); #endif
#endif // MULTIHEAP
}
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::Sync, public
//
// Synopsis: Sync memory to global state.
//
// Arguments: None.
//
// Returns: Appropriate status code
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
//
//----------------------------------------------------------------------------
inline SCODE CSmAllocator::Sync(void) { SCODE sc = S_OK; #if !defined(_CHICAGO_)
#if !defined(MULTIHEAP)
if (!_smb.IsSynced()) { CLockDfMutex lckdmtx(_dmtx);
sc = _smb.Sync(); _cbSize = _smb.GetSize(); } #else
if (_psmb) { if (!_psmb->IsSynced()) { sc = _psmb->Sync(); } _cbSize = _psmb->GetSize(); } #endif
#endif
return sc; }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::IncrementLuid, public
//
// Synopsis: Increments the global LUID
//
// Arguments: None.
//
// Returns: Appropriate status code
//
// History: 06-Apr-95 HenryLee Created
//----------------------------------------------------------------------------
inline DFLUID CSmAllocator::IncrementLuid(void) { #if !defined(MULTIHEAP)
CLockDfMutex lckdmx(_dmtx); #endif
#ifdef _CHICAGO_
//
// On Chicago, we merely increment the globally available
// LUID to the next value.
//
return ++gs_dfluid; #else
return _pbBase ? GetHeader()->IncrementLuid() : InterlockedIncrement((LONG*)&gs_dfluid); #endif
}
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetBase, public
//
// Synopsis: Return pointer to base of heap
//
// History: 29-Mar-94 PhilipLa Created
// 05-Feb-95 KentCe Use Win95 Shared Heap.
//
//----------------------------------------------------------------------------
inline void * CSmAllocator::GetBase(void) { #if defined(_CHICAGO_)
return NULL; #else
return _pbBase; #endif
}
#if !defined(MULTIHEAP)
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetMutex, public
//
// Synopsis: Return a pointer to the Mutex
//
// History: 19-Jul-95 SusiA Created
//
//----------------------------------------------------------------------------
inline CDfMutex * CSmAllocator::GetMutex(void) { return &_dmtx; } #endif
//
// Take advantage of Windows 95 Shared Heap.
//
#if !defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetAddress, private
//
// Synopsis: Returns an address given an offset from the base
//
// Arguments: [ulOffset] -- Offset to convert to address
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline CBlockHeader * CSmAllocator::GetAddress(SIZE_T ulOffset) const { return (ulOffset == 0) ? NULL : (CBlockHeader *)(_pbBase + ulOffset); }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetOffset
//
// Synopsis: Returns a byte offset from the base given a pointer
//
// Arguments: [pbh] -- Pointer to convert to offset
//
// History: 29-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline ULONG CSmAllocator::GetOffset(CBlockHeader *pbh) const { memAssert((BYTE *)pbh >= _pbBase && (BYTE*)pbh < _pbBase + _cbSize); return (ULONG)((ULONG_PTR)pbh - (ULONG_PTR)_pbBase); }
//+---------------------------------------------------------------------------
//
// Member: CSmAllocator::GetHeader, private
//
// Synopsis: Return pointer to CHeapHeader for this heap
//
// History: 30-Mar-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline CHeapHeader * CSmAllocator::GetHeader(void) { return (CHeapHeader *)_pbBase; }
#ifdef MULTIHEAP
//+-------------------------------------------------------------------------
//
// Member: CSmAllocator::HeapName, public
//
// Synopsis: Return the luid part of the shared heap name
//
// History: 30-Nov-95 HenryLee Created
//
//--------------------------------------------------------------------------
inline const ULONG CSmAllocator::GetHeapName() { return _ulHeapName; } #endif
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::ResetAllocedBlocks, public
//
// Synopsis: Reset the allocated block counter
//
// History: 04-Apr-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline void CHeapHeader::ResetAllocedBlocks(void) { _ulAllocedBlocks = 0; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::IncrementAllocedBlocks, public
//
// Synopsis: Increment the allocated block count
//
// History: 04-Apr-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline SIZE_T CHeapHeader::IncrementAllocedBlocks(void) { return ++_ulAllocedBlocks; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::DecrementAllocedBlocks, public
//
// Synopsis: Decrement the allocated block count
//
// History: 04-Apr-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline SIZE_T CHeapHeader::DecrementAllocedBlocks(void) { return --_ulAllocedBlocks; }
//+---------------------------------------------------------------------------
//
// Member: CHeapHeader::GetAllocedBlocks, public
//
// Synopsis: Return the allocated block count
//
// History: 04-Apr-94 PhilipLa Created
//
//----------------------------------------------------------------------------
inline SIZE_T CHeapHeader::GetAllocedBlocks(void) { return _ulAllocedBlocks; }
#endif // !defined(_CHICAGO_)
#endif // #ifndef __HEAP_HXX__
|