1134 lines
27 KiB
C++
1134 lines
27 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
||
|
//
|
||
|
// File: Mem.CXX
|
||
|
//
|
||
|
// Contents: Memory tracking code
|
||
|
//
|
||
|
// Classes: CMemAlloc
|
||
|
//
|
||
|
// Functions: DfCreateSharedAllocator
|
||
|
// DfPrintAllocs
|
||
|
// DfGetMemAlloced
|
||
|
//
|
||
|
// History: 17-May-93 AlexT Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include <dfhead.cxx>
|
||
|
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if defined(WIN32)
|
||
|
|
||
|
#include <smalloc.hxx>
|
||
|
#include <olesem.hxx>
|
||
|
|
||
|
// This global variable holds the base address of the shared memory region.
|
||
|
// It is required by the based pointer stuff and is accessed directly.
|
||
|
// Initialisation is a side effect of calling DfCreateSharedAllocator or
|
||
|
// DfSyncSharedMemory (BUGBUG: or will be, when the based pointer stuff
|
||
|
// is checked in).
|
||
|
|
||
|
#ifdef MULTIHEAP
|
||
|
//__declspec(thread) void *DFBASEPTR = NULL;
|
||
|
#else
|
||
|
void *DFBASEPTR = NULL;
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if DBG == 1
|
||
|
#include <dfdeb.hxx>
|
||
|
|
||
|
#ifdef _M_I286
|
||
|
#include <dos.h>
|
||
|
#include <toolhelp.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef WIN32
|
||
|
// Multithread protection for allocation list
|
||
|
CStaticDfMutex _sdmtxAllocs(TSTR("DfAllocList"));
|
||
|
|
||
|
#define TAKE_ALLOCS_MUTEX olVerSucc(_sdmtxAllocs.Take(INFINITE))
|
||
|
#define RELEASE_ALLOCS_MUTEX _sdmtxAllocs.Release()
|
||
|
#else
|
||
|
#define TAKE_ALLOCS_MUTEX
|
||
|
#define RELEASE_ALLOCS_MUTEX
|
||
|
#endif
|
||
|
|
||
|
#define GET_ALLOC_LIST_HEAD ((CMemAlloc *)DfGetResLimit(DBRI_ALLOC_LIST))
|
||
|
#define SET_ALLOC_LIST_HEAD(pma) DfSetResLimit(DBRI_ALLOC_LIST, (LONG)(pma))
|
||
|
|
||
|
#define DEB_MEMORY 0x01000000
|
||
|
#define DEB_LEAKS 0x01100000
|
||
|
|
||
|
const int NEWMEM = 0xDEDE;
|
||
|
const int OLDMEM = 0xEDED;
|
||
|
|
||
|
//+--------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CMemAlloc (ma)
|
||
|
//
|
||
|
// Purpose: Tracks memory allocations
|
||
|
//
|
||
|
// Interface: See below
|
||
|
//
|
||
|
// History: 08-Jul-92 DrewB Created
|
||
|
// 17-May-93 AlexT Add idContext
|
||
|
//
|
||
|
//---------------------------------------------------------------
|
||
|
|
||
|
class CMemAlloc
|
||
|
{
|
||
|
public:
|
||
|
void *pvCaller;
|
||
|
ULONG cbSize;
|
||
|
void *pvMem;
|
||
|
ContextId idContext;
|
||
|
CMemAlloc *pmaPrev, *pmaNext;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AddAlloc, private
|
||
|
//
|
||
|
// Synopsis: Puts an allocation into the allocation list
|
||
|
//
|
||
|
// Arguments: [pma] - Allocation descriptor
|
||
|
// [pvCaller] - Allocator
|
||
|
// [cbSize] - Real size
|
||
|
// [pvMem] - Memory block
|
||
|
// [cid] - Context ID
|
||
|
//
|
||
|
// History: 11-Jan-94 DrewB Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#if DBG == 1
|
||
|
static void AddAlloc(CMemAlloc *pma, void *pvCaller, ULONG cbSize,
|
||
|
void *pvMem, ContextId cid)
|
||
|
{
|
||
|
pma->pvCaller = pvCaller;
|
||
|
pma->cbSize = cbSize;
|
||
|
pma->pvMem = pvMem;
|
||
|
pma->idContext = cid;
|
||
|
|
||
|
#ifdef MEMTRACK
|
||
|
TAKE_ALLOCS_MUTEX;
|
||
|
|
||
|
pma->pmaNext = GET_ALLOC_LIST_HEAD;
|
||
|
if (pma->pmaNext)
|
||
|
pma->pmaNext->pmaPrev = pma;
|
||
|
pma->pmaPrev = NULL;
|
||
|
olAssert(!IsBadReadPtr(pma, sizeof(CMemAlloc)));
|
||
|
SET_ALLOC_LIST_HEAD(pma);
|
||
|
|
||
|
RELEASE_ALLOCS_MUTEX;
|
||
|
|
||
|
ModifyResLimit(DBRQ_MEMORY_ALLOCATED, (LONG)cbSize);
|
||
|
|
||
|
olDebugOut((DEB_MEMORY, "%s alloced %p:%lu, total %ld\n",
|
||
|
cid != 0 ? "Task" : "Shrd",
|
||
|
pvMem, pma->cbSize, DfGetResLimit(DBRQ_MEMORY_ALLOCATED)));
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RemoveAlloc, private
|
||
|
//
|
||
|
// Synopsis: Takes an allocation out of the allocation list
|
||
|
//
|
||
|
// Arguments: [pma] - Allocation descriptor
|
||
|
// [pvMem] - Real allocation
|
||
|
// [cid] - Context ID
|
||
|
//
|
||
|
// History: 11-Jan-94 DrewB Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#if DBG == 1
|
||
|
static void RemoveAlloc(CMemAlloc *pma, void *pvMem, ContextId cid)
|
||
|
{
|
||
|
#ifdef MEMTRACK
|
||
|
olAssert(pma->pvMem == pvMem && aMsg("Address mismatch"));
|
||
|
olAssert(pma->idContext == cid && aMsg("Context mismatch"));
|
||
|
|
||
|
TAKE_ALLOCS_MUTEX;
|
||
|
|
||
|
olAssert(pma->pmaNext == NULL ||
|
||
|
!IsBadReadPtr(pma->pmaNext, sizeof(CMemAlloc)));
|
||
|
olAssert(pma->pmaPrev == NULL ||
|
||
|
!IsBadReadPtr(pma->pmaPrev, sizeof(CMemAlloc)));
|
||
|
if (pma->pmaPrev)
|
||
|
{
|
||
|
pma->pmaPrev->pmaNext = pma->pmaNext;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SET_ALLOC_LIST_HEAD(pma->pmaNext);
|
||
|
}
|
||
|
if (pma->pmaNext)
|
||
|
{
|
||
|
pma->pmaNext->pmaPrev = pma->pmaPrev;
|
||
|
}
|
||
|
|
||
|
RELEASE_ALLOCS_MUTEX;
|
||
|
|
||
|
ModifyResLimit(DBR_MEMORY, (LONG)pma->cbSize);
|
||
|
|
||
|
ModifyResLimit(DBRQ_MEMORY_ALLOCATED, -(LONG)pma->cbSize);
|
||
|
olAssert(DfGetResLimit(DBRQ_MEMORY_ALLOCATED) >= 0);
|
||
|
|
||
|
olDebugOut((DEB_MEMORY, "%s freed %p:%lu, total %ld\n",
|
||
|
cid != 0 ? "Task" : "Shrd",
|
||
|
pma->pvMem, pma->cbSize,
|
||
|
DfGetResLimit(DBRQ_MEMORY_ALLOCATED)));
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfGetMemAlloced, private
|
||
|
//
|
||
|
// Synopsis: Returns the amount of memory currently allocated
|
||
|
//
|
||
|
// History: 08-Jul-92 DrewB Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDAPI_(LONG) DfGetMemAlloced(void)
|
||
|
{
|
||
|
return DfGetResLimit(DBRQ_MEMORY_ALLOCATED);
|
||
|
}
|
||
|
|
||
|
//+--------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfPrintAllocs, private
|
||
|
//
|
||
|
// Synopsis: Walks the allocation list and prints out their info
|
||
|
//
|
||
|
// History: 08-Jul-92 DrewB Created
|
||
|
//
|
||
|
//---------------------------------------------------------------
|
||
|
|
||
|
STDAPI_(void) DfPrintAllocs(void)
|
||
|
{
|
||
|
#ifdef MEMTRACK
|
||
|
CMemAlloc *pma;
|
||
|
|
||
|
olDebugOut((DEB_ITRACE, "In DfPrintAllocs()\n"));
|
||
|
|
||
|
TAKE_ALLOCS_MUTEX;
|
||
|
|
||
|
pma = GET_ALLOC_LIST_HEAD;
|
||
|
while (pma != NULL)
|
||
|
{
|
||
|
#ifdef _M_I286
|
||
|
HGLOBAL hgbCode;
|
||
|
GLOBALENTRY ge;
|
||
|
|
||
|
hgbCode = LOWORD(GlobalHandle(_FP_SEG(pma->pvCaller)));
|
||
|
ge.dwSize = sizeof(ge);
|
||
|
|
||
|
if (hgbCode == 0 || !GlobalEntryHandle(&ge, hgbCode) ||
|
||
|
ge.wType != GT_CODE)
|
||
|
olDebugOut((DEB_LEAKS, "Alloc: %p alloc %p:%4lu bytes\n",
|
||
|
pma->pvCaller, pma->pvMem, pma->cbSize));
|
||
|
else
|
||
|
// The (unsigned short)(unsigned long) cast is necessary
|
||
|
// to avoid a compiler warning. We want the offset of
|
||
|
// the pointer which is an unsigned short. A direct
|
||
|
// cast results in a "segment lost" warning. Casting
|
||
|
// to unsigned long first avoids this unnecessary warning
|
||
|
olDebugOut((DEB_LEAKS,
|
||
|
"Alloc %s: %2X:%04X alloc %p:%4lu bytes\n",
|
||
|
pma->idContext ? "LOCAL" : "SHARED",
|
||
|
ge.wData, (unsigned short)(unsigned long)pma->pvCaller,
|
||
|
pma->pvMem, pma->cbSize));
|
||
|
#else
|
||
|
olDebugOut((DEB_LEAKS, "Alloc %s: %p alloc %p:%4lu bytes\n",
|
||
|
pma->idContext ? "LOCAL" : "SHARED",
|
||
|
pma->pvCaller, pma->pvMem, pma->cbSize));
|
||
|
#endif
|
||
|
pma = pma->pmaNext;
|
||
|
}
|
||
|
|
||
|
RELEASE_ALLOCS_MUTEX;
|
||
|
|
||
|
olDebugOut((DEB_ITRACE, "Out DfPrintAllocs\n"));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef MULTIHEAP
|
||
|
|
||
|
CSmAllocator g_SmAllocator; // optimization for single threaded case
|
||
|
CErrorSmAllocator g_ErrorSmAllocator;
|
||
|
CSharedMemoryBlock g_smb; // optimize single threaded case
|
||
|
ULONG g_ulHeapName = 0; // name of the above heap
|
||
|
TEB * g_pteb = NtCurrentTeb();
|
||
|
|
||
|
CSmAllocator& GetTlsSmAllocator()
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
COleTls otls(hr); // even for main thread, we need to initialize TLS
|
||
|
memAssert (SUCCEEDED(hr) && "Error initializing TLS");
|
||
|
|
||
|
if (g_pteb == NtCurrentTeb())
|
||
|
{
|
||
|
// return the static global allocator for main thread
|
||
|
// DoThreadSpecificCleanup does not deallocate this allocator
|
||
|
return g_SmAllocator;
|
||
|
}
|
||
|
|
||
|
if (otls->pSmAllocator == NULL)
|
||
|
{
|
||
|
if ((otls->pSmAllocator = new CSmAllocator()) == NULL)
|
||
|
otls->pSmAllocator = &g_ErrorSmAllocator;
|
||
|
// DoThreadSpecificCleanup will deallocate this when thread goes away
|
||
|
}
|
||
|
return *(otls->pSmAllocator);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This initialization used to be done in the global allocator
|
||
|
// which is now a per thread allocator
|
||
|
//
|
||
|
class CResourceCriticalSection
|
||
|
{
|
||
|
public:
|
||
|
CResourceCriticalSection ()
|
||
|
{
|
||
|
InitializeCriticalSection(&g_csScratchBuffer);
|
||
|
#ifdef COORD
|
||
|
InitializeCriticalSection(&g_csResourceList);
|
||
|
#endif
|
||
|
}
|
||
|
~CResourceCriticalSection ()
|
||
|
{
|
||
|
DeleteCriticalSection(&g_csScratchBuffer);
|
||
|
#ifdef COORD
|
||
|
DeleteCriticalSection(&g_csResourceList);
|
||
|
#endif
|
||
|
}
|
||
|
};
|
||
|
CResourceCriticalSection g_ResourceCriticalSection;
|
||
|
|
||
|
#else
|
||
|
CSmAllocator g_smAllocator;
|
||
|
#endif // MULTIHEAP
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CMallocBased::operator new, public
|
||
|
//
|
||
|
// Synopsis: Overridden allocator
|
||
|
//
|
||
|
// Effects: Allocates memory from given allocator
|
||
|
//
|
||
|
// Arguments: [size] -- byte count to allocate
|
||
|
// [pMalloc] -- allocator
|
||
|
//
|
||
|
// Returns: memory block address
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 21-May-93 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef CODESEGMENTS
|
||
|
#pragma code_seg(SEG_CMallocBased_new)
|
||
|
#endif
|
||
|
|
||
|
void *CMallocBased::operator new(size_t size, IMalloc * const pMalloc)
|
||
|
|
||
|
{
|
||
|
#ifndef WIN32
|
||
|
olAssert(DfGetResLimit(DBRQ_MEMORY_ALLOCATED) >= 0);
|
||
|
#endif
|
||
|
olAssert(size > 0);
|
||
|
|
||
|
#if DBG==1
|
||
|
if (SimulateFailure(DBF_MEMORY))
|
||
|
{
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
if (!HaveResource(DBR_MEMORY, (LONG)size))
|
||
|
{
|
||
|
// Artificial limit exceeded so force failure
|
||
|
return NULL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void *pv = g_smAllocator.Alloc(
|
||
|
#if DBG==1
|
||
|
sizeof(CMemAlloc) +
|
||
|
#endif
|
||
|
size);
|
||
|
|
||
|
if (pv == NULL)
|
||
|
{
|
||
|
#if DBG==1
|
||
|
ModifyResLimit(DBR_MEMORY, (LONG)size);
|
||
|
#endif
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#if DBG==1
|
||
|
memset(pv, NEWMEM, sizeof(CMemAlloc) + size);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
#if DBG==1
|
||
|
// Put debug info in buffer
|
||
|
// Note: This assumes CMemAlloc will end up properly aligned
|
||
|
CMemAlloc *pma = (CMemAlloc *) pv;
|
||
|
pv = (void *) ((CMemAlloc *) pv + 1);
|
||
|
|
||
|
AddAlloc(pma, *(((void **)&size)-1), size, pv, 0);
|
||
|
#endif
|
||
|
|
||
|
return pv;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CMallocBased::operator delete
|
||
|
//
|
||
|
// Synopsis: Overridden deallocator
|
||
|
//
|
||
|
// Effects: Frees memory block
|
||
|
//
|
||
|
// Arguments: [pv] -- memory block address
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 21-May-93 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef CODESEGMENTS
|
||
|
#pragma code_seg(SEG_CMallocBased_delete)
|
||
|
#endif
|
||
|
|
||
|
void CMallocBased::operator delete(void *pv)
|
||
|
|
||
|
{
|
||
|
if (pv == NULL)
|
||
|
return;
|
||
|
|
||
|
#if DBG==1
|
||
|
// Assumes ma ends up properly aligned
|
||
|
CMemAlloc *pma = (CMemAlloc *) pv;
|
||
|
pma--;
|
||
|
|
||
|
RemoveAlloc(pma, pv, 0);
|
||
|
|
||
|
pv = (void *) pma;
|
||
|
|
||
|
memset(pv, OLDMEM, (size_t) pma->cbSize);
|
||
|
#endif
|
||
|
|
||
|
g_smAllocator.Free(pv);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CMallocBased::deleteNoMutex
|
||
|
//
|
||
|
// Synopsis: deallocator function without Mutex
|
||
|
//
|
||
|
// Effects: Frees memory block
|
||
|
//
|
||
|
// Arguments: [pv] -- memory block address
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 19-Jul-95 SusiA Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef CODESEGMENTS
|
||
|
#pragma code_seg(SEG_CMallocBased_deleteNoMutex)
|
||
|
#endif
|
||
|
|
||
|
void CMallocBased::deleteNoMutex(void *pv)
|
||
|
|
||
|
{
|
||
|
if (pv == NULL)
|
||
|
return;
|
||
|
|
||
|
#if DBG==1
|
||
|
// Assumes ma ends up properly aligned
|
||
|
CMemAlloc *pma = (CMemAlloc *) pv;
|
||
|
pma--;
|
||
|
|
||
|
RemoveAlloc(pma, pv, 0);
|
||
|
|
||
|
pv = (void *) pma;
|
||
|
|
||
|
memset(pv, OLDMEM, (size_t) pma->cbSize);
|
||
|
#endif
|
||
|
|
||
|
g_smAllocator.FreeNoMutex(pv);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#if !defined(WIN32) && DBG==1
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CSharedMalloc
|
||
|
//
|
||
|
// Purpose: Track shared allocators
|
||
|
//
|
||
|
// Interface: IMalloc
|
||
|
//
|
||
|
// History: 28-May-93 AlexT Created
|
||
|
//
|
||
|
// Notes: This is only for builds that use CoCreateStandardMalloc
|
||
|
// (which is non-WIN32 builds for now). We inherit from
|
||
|
// CMallocBased to pick up memory tracking.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
class CSharedMalloc : public IMalloc, public CMallocBased
|
||
|
{
|
||
|
public:
|
||
|
CSharedMalloc(IMalloc *pMalloc);
|
||
|
|
||
|
// *** IUnknown methods ***
|
||
|
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj);
|
||
|
STDMETHOD_(ULONG,AddRef) (THIS);
|
||
|
STDMETHOD_(ULONG,Release) (THIS);
|
||
|
|
||
|
// *** IMalloc methods ***
|
||
|
STDMETHOD_(void FAR*, Alloc) (THIS_ ULONG cb);
|
||
|
STDMETHOD_(void FAR*, Realloc) (THIS_ void FAR* pv, ULONG cb);
|
||
|
STDMETHOD_(void, Free) (THIS_ void FAR* pv);
|
||
|
STDMETHOD_(ULONG, GetSize) (THIS_ void FAR* pv);
|
||
|
STDMETHOD_(int, DidAlloc) (THIS_ void FAR* pv);
|
||
|
STDMETHOD_(void, HeapMinimize) (THIS);
|
||
|
|
||
|
private:
|
||
|
IMalloc * const _pMalloc;
|
||
|
};
|
||
|
|
||
|
CSharedMalloc::CSharedMalloc(IMalloc *pMalloc)
|
||
|
: _pMalloc(pMalloc)
|
||
|
{
|
||
|
_pMalloc->AddRef();
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CSharedMalloc::QueryInterface(THIS_ REFIID riid, LPVOID FAR* ppvObj)
|
||
|
{
|
||
|
olAssert(!aMsg("CSharedMalloc::QueryInterface unsupported"));
|
||
|
return(ResultFromScode(E_UNEXPECTED));
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedMalloc::AddRef (THIS)
|
||
|
{
|
||
|
return(_pMalloc->AddRef());
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedMalloc::Release (THIS)
|
||
|
{
|
||
|
ULONG cRef = _pMalloc->Release();
|
||
|
|
||
|
if (cRef == 0)
|
||
|
delete this;
|
||
|
|
||
|
return (ULONG) cRef;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(void FAR*) CSharedMalloc::Alloc (THIS_ ULONG cb)
|
||
|
{
|
||
|
return _pMalloc->Alloc(cb);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(void FAR*) CSharedMalloc::Realloc (THIS_ void FAR* pv, ULONG cb)
|
||
|
{
|
||
|
olAssert(!aMsg("CSharedMalloc::Realloc unsupported"));
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(void) CSharedMalloc::Free (THIS_ void FAR* pv)
|
||
|
{
|
||
|
_pMalloc->Free(pv);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CSharedMalloc::GetSize (THIS_ void FAR* pv)
|
||
|
{
|
||
|
olAssert(!aMsg("CSharedMalloc::GetSize unsupported"));
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(int) CSharedMalloc::DidAlloc (THIS_ void FAR* pv)
|
||
|
{
|
||
|
olAssert(!aMsg("CSharedMalloc::DidAlloc unsupported"));
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(void) CSharedMalloc::HeapMinimize (THIS)
|
||
|
{
|
||
|
olAssert(!aMsg("CSharedMalloc::HeapMinimize unsupported"));
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#if defined(WIN32)
|
||
|
|
||
|
// -------------- Shared memory allocator stuff for Win32 ---------------
|
||
|
|
||
|
|
||
|
|
||
|
typedef HRESULT InitSmFn ( IMalloc ** ppm );
|
||
|
extern HRESULT NullInitSm ( IMalloc ** ppm );
|
||
|
extern HRESULT InitSharedAllocator ( IMalloc ** ppm);
|
||
|
#ifdef MULTIHEAP
|
||
|
extern HRESULT InitMultipleSharedAllocator (IMalloc ** ppm );
|
||
|
InitSmFn * DfCreateSharedAllocator = InitMultipleSharedAllocator;
|
||
|
#else
|
||
|
InitSmFn * DfCreateSharedAllocator = InitSharedAllocator;
|
||
|
#endif
|
||
|
|
||
|
#if !defined(MULTIHEAP)
|
||
|
COleStaticMutexSem mxsInitSm;
|
||
|
BOOL fInitialisedSm = FALSE;
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InitSharedAllocator
|
||
|
//
|
||
|
// Synopsis: Initialises the shared memory region for this process.
|
||
|
//
|
||
|
// Arguments: [ppm] -- return address for shared memory IMalloc*
|
||
|
//
|
||
|
// Returns: status code
|
||
|
//
|
||
|
// History: 27-May-94 MikeSe Created
|
||
|
//
|
||
|
// Notes: This routine is called indirectly through DfCreateSharedAllocator, in
|
||
|
// such a way that in most circumstances it will be executed
|
||
|
// exactly once per process. (Because we overwrite the contents
|
||
|
// of DfCreateSharedAllocator if successful).
|
||
|
//
|
||
|
// However, in order to be multi-thread safe, we need a process
|
||
|
// mutex to prevent execution of the initialisation code twice.
|
||
|
//
|
||
|
// Furthermore, since we are initialising system-wide state
|
||
|
// (namely the shared memory region) we must provide cross-process
|
||
|
// mutual exclusion over this activity.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT InitSharedAllocator (
|
||
|
IMalloc ** ppm )
|
||
|
{
|
||
|
// multi-thread safety
|
||
|
|
||
|
mxsInitSm.Request();
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if ( !fInitialisedSm )
|
||
|
{
|
||
|
// We need to do the initialisation. Obtain exclusion against
|
||
|
// other processes.
|
||
|
|
||
|
SECURITY_ATTRIBUTES secattr;
|
||
|
secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||
|
#ifndef _CHICAGO_
|
||
|
CWorldSecurityDescriptor wsd;
|
||
|
secattr.lpSecurityDescriptor = &wsd;
|
||
|
#else
|
||
|
secattr.lpSecurityDescriptor = NULL;
|
||
|
#endif // !_CHICAGO_
|
||
|
secattr.bInheritHandle = FALSE;
|
||
|
|
||
|
HANDLE hMutex = CreateMutex ( &secattr, FALSE, TEXT("OleDfSharedMemoryMutex"));
|
||
|
if ( hMutex != NULL )
|
||
|
{
|
||
|
WaitForSingleObject ( hMutex, INFINITE );
|
||
|
hr = g_smAllocator.Init ( DOCFILE_SM_NAME );
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
*ppm = &g_smAllocator;
|
||
|
// Also set up base address
|
||
|
#ifdef USEBASED
|
||
|
DFBASEPTR = g_smAllocator.GetBase();
|
||
|
#endif
|
||
|
DfCreateSharedAllocator = NullInitSm;
|
||
|
fInitialisedSm = TRUE;
|
||
|
}
|
||
|
ReleaseMutex ( hMutex );
|
||
|
}
|
||
|
else
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
}
|
||
|
else // fInitialisedSm is TRUE
|
||
|
{
|
||
|
*ppm = &g_smAllocator;
|
||
|
}
|
||
|
mxsInitSm.Release();
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: NullInitSm
|
||
|
//
|
||
|
// Synopsis: Second and subsequent times handler for DfCreateSharedAllocator
|
||
|
//
|
||
|
// Effects: Simply returns pointer to g_smAllocator.
|
||
|
//
|
||
|
// Arguments: [ppm] -- return address for shared memory IMalloc*
|
||
|
//
|
||
|
// Returns: S_OK
|
||
|
//
|
||
|
// History: 27-May-94 MikeSe Created
|
||
|
//
|
||
|
// Notes: This function cannot be called unless we successfully
|
||
|
// initialise the shared memory (because we do not overwrite
|
||
|
// the contents of DfCreateSharedAllocator until then).
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT NullInitSm (
|
||
|
IMalloc **ppm )
|
||
|
{
|
||
|
*ppm = &g_smAllocator;
|
||
|
return S_OK;
|
||
|
}
|
||
|
#endif // !defined(MULTIHEAP)
|
||
|
|
||
|
#ifdef MULTIHEAP
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InitMultipleSharedAllocator
|
||
|
//
|
||
|
// Synopsis: Initialises a shared memory region for this process.
|
||
|
//
|
||
|
// Arguments: [ppm] -- return address for shared memory IMalloc*
|
||
|
//
|
||
|
// Returns: status code
|
||
|
//
|
||
|
// History: 20-Nov-95 HenryLee Created
|
||
|
//
|
||
|
// Notes: This routine is called indirectly by DfCreateSharedAllocator
|
||
|
// such a way that in most circumstances it will be executed
|
||
|
// exactly once per docfile open.
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT InitMultipleSharedAllocator (IMalloc ** ppm )
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
CSmAllocator *pMalloc = &g_smAllocator;
|
||
|
*ppm = NULL;
|
||
|
|
||
|
if (DFBASEPTR == NULL) // allocate a new heap
|
||
|
{
|
||
|
LUID luid; // generate a unique name
|
||
|
if (AllocateLocallyUniqueId (&luid) == FALSE)
|
||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||
|
|
||
|
// reset the allocator state to initialize it properly
|
||
|
pMalloc->SetState (NULL, NULL, NULL, NULL, 0);
|
||
|
|
||
|
hr = pMalloc->Init ( luid.LowPart, FALSE );
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
*ppm = pMalloc;
|
||
|
DFBASEPTR = pMalloc->GetBase();
|
||
|
pMalloc->AddRef();
|
||
|
}
|
||
|
}
|
||
|
else // use an existing heap
|
||
|
*ppm = pMalloc;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfSyncSharedMemory, public
|
||
|
//
|
||
|
// Synopsis: Sync up shared memory
|
||
|
//
|
||
|
// Returns: Appropriate status code
|
||
|
//
|
||
|
// History: 08-Apr-94 PhilipLa Created
|
||
|
//
|
||
|
// Notes: BUGBUG should play pointer game here too
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#ifdef MULTIHEAP
|
||
|
SCODE DfSyncSharedMemory(ULONG ulHeapName)
|
||
|
#else
|
||
|
SCODE DfSyncSharedMemory(void)
|
||
|
#endif
|
||
|
{
|
||
|
// make sure we have initialised
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
#ifdef MULTIHEAP
|
||
|
CSmAllocator *pMalloc = &g_smAllocator;
|
||
|
if (ulHeapName != 0) // reopen a shared heap for unmarshaling
|
||
|
{
|
||
|
// reset the allocator state to initialize it properly
|
||
|
pMalloc->SetState (NULL, NULL, NULL, NULL, 0);
|
||
|
|
||
|
hr = pMalloc->Init ( ulHeapName, TRUE);
|
||
|
DFBASEPTR = pMalloc->GetBase();
|
||
|
|
||
|
}
|
||
|
else // try to create a new shared heap
|
||
|
#else
|
||
|
if (!fInitialisedSm)
|
||
|
#endif // MULTIHEAP
|
||
|
{
|
||
|
IMalloc * pm;
|
||
|
hr = DfCreateSharedAllocator ( &pm );
|
||
|
}
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
#ifdef MULTIHEAP
|
||
|
hr = pMalloc->Sync();
|
||
|
#else
|
||
|
hr = g_smAllocator.Sync();
|
||
|
#endif
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfInitSharedMemBase, public
|
||
|
//
|
||
|
// Synopsis: Set up the base of shared memory
|
||
|
//
|
||
|
// History: 31-May-94 MikeSe Created
|
||
|
//
|
||
|
// Notes: BUGBUG this may go away
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DfInitSharedMemBase()
|
||
|
{
|
||
|
#ifdef MULTIHEAP
|
||
|
HRESULT hr;
|
||
|
COleTls otls(hr);
|
||
|
memAssert (SUCCEEDED(hr) && "Error initializing TLS");
|
||
|
|
||
|
DFBASEPTR = NULL; // this will force a heap to be allocated
|
||
|
// when DfCreateSharedAllocator is called
|
||
|
#else
|
||
|
// make sure we have initialised. This is sufficient to ensure
|
||
|
// that DFBASEPTR is set up
|
||
|
if (!fInitialisedSm)
|
||
|
{
|
||
|
IMalloc * pm;
|
||
|
HRESULT hr = DfCreateSharedAllocator ( &pm );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#elif DBG==1
|
||
|
|
||
|
// Win16, debug only shared memory stuff
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DfCreateSharedAllocator
|
||
|
//
|
||
|
// Synopsis: Create shared memory tracking allocator
|
||
|
//
|
||
|
// Effects:
|
||
|
//
|
||
|
// Arguments: [ppm] -- place holder for returned IMalloc instance
|
||
|
//
|
||
|
// Returns: HRESULT
|
||
|
//
|
||
|
// Algorithm:
|
||
|
//
|
||
|
// History: 17-May-93 AlexT Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT DfCreateSharedAllocator(IMalloc **ppm)
|
||
|
{
|
||
|
SCODE sc;
|
||
|
IMalloc *pMallocNew, *pMallocShare;
|
||
|
|
||
|
olHChk(CoCreateStandardMalloc(MEMCTX_SHARED, &pMallocNew));
|
||
|
olHChkTo(EH_New, CoGetMalloc(MEMCTX_SHARED, &pMallocShare));
|
||
|
olMemTo(EH_Share, *ppm = new (pMallocShare) CSharedMalloc(pMallocNew));
|
||
|
|
||
|
EH_Share:
|
||
|
pMallocShare->Release();
|
||
|
EH_New:
|
||
|
pMallocNew->Release();
|
||
|
EH_Err:
|
||
|
return(ResultFromScode(sc));
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// BUGBUG re-enable debug allocator with shared heap support
|
||
|
#if DBG==1 && !defined(MULTIHEAP)
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CLocalAlloc::operator new, public
|
||
|
//
|
||
|
// Synopsis: Overloaded new operator to allocate objects from
|
||
|
// task local space.
|
||
|
//
|
||
|
// Arguments: [size] -- Size of block to allocate
|
||
|
//
|
||
|
// Returns: Pointer to memory allocated.
|
||
|
//
|
||
|
// History: 17-Aug-92 PhilipLa Created.
|
||
|
// 18-May-93 AlexT Switch to task IMalloc
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void *CLocalAlloc::operator new(size_t size)
|
||
|
{
|
||
|
#ifndef WIN32
|
||
|
olAssert(DfGetResLimit(DBRQ_MEMORY_ALLOCATED) >= 0);
|
||
|
#endif
|
||
|
olAssert(size > 0);
|
||
|
|
||
|
if (SimulateFailure(DBF_MEMORY))
|
||
|
{
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
if (!HaveResource(DBR_MEMORY, (LONG)size))
|
||
|
{
|
||
|
// Artificial limit exceeded so force failure
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void *pv = TaskMemAlloc(sizeof(CMemAlloc *) + size);
|
||
|
|
||
|
if (pv != NULL)
|
||
|
{
|
||
|
void * const pvOrig = pv;
|
||
|
|
||
|
memset(pv, NEWMEM, sizeof(CMemAlloc *) + size);
|
||
|
|
||
|
CMemAlloc *pma = NULL;
|
||
|
|
||
|
// Allocate tracking block (with shared memory)
|
||
|
IMalloc *pMalloc;
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#ifdef MULTIHEAP
|
||
|
pMalloc = &g_smAllocator;
|
||
|
#else
|
||
|
if ( FAILED(DfCreateSharedAllocator ( &pMalloc )) )
|
||
|
pMalloc = NULL;
|
||
|
#endif // MULTIHEAP
|
||
|
#else
|
||
|
if (FAILED(DfGetScode(CoGetMalloc(MEMCTX_SHARED, &pMalloc))))
|
||
|
pMalloc = NULL;
|
||
|
#endif
|
||
|
|
||
|
if (pMalloc)
|
||
|
{
|
||
|
pma = (CMemAlloc *) pMalloc->Alloc(sizeof(CMemAlloc));
|
||
|
if (pma != NULL)
|
||
|
{
|
||
|
memset(pma, NEWMEM, sizeof(CMemAlloc));
|
||
|
CMemAlloc **ppma = (CMemAlloc **) pv;
|
||
|
pv = (void *) ((CMemAlloc **)pv + 1);
|
||
|
*ppma = pma;
|
||
|
|
||
|
AddAlloc(pma, *(((void **)&size)-1), size, pv,
|
||
|
GetCurrentContextId());
|
||
|
}
|
||
|
|
||
|
pMalloc->Release();
|
||
|
}
|
||
|
|
||
|
if (pma == NULL)
|
||
|
{
|
||
|
// Couldn't allocate tracking block - fail allocation
|
||
|
TaskMemFree(pvOrig);
|
||
|
pv = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pv == NULL)
|
||
|
{
|
||
|
ModifyResLimit(DBR_MEMORY, (LONG)size);
|
||
|
}
|
||
|
|
||
|
return(pv);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: CLocalAlloc::operator delete, public
|
||
|
//
|
||
|
// Synopsis: Free memory from task local space
|
||
|
//
|
||
|
// Arguments: [pv] -- Pointer to memory to free
|
||
|
//
|
||
|
// History: 17-Aug-92 PhilipLa Created.
|
||
|
// 18-May-93 AlexT Switch to task IMalloc
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void CLocalAlloc::operator delete(void *pv)
|
||
|
{
|
||
|
if (pv == NULL)
|
||
|
return;
|
||
|
|
||
|
CMemAlloc **ppma = (CMemAlloc **)pv;
|
||
|
ppma--;
|
||
|
|
||
|
CMemAlloc *pma = *ppma;
|
||
|
|
||
|
RemoveAlloc(pma, pv, GetCurrentContextId());
|
||
|
|
||
|
pv = (void *) ppma;
|
||
|
memset(pv, OLDMEM, (size_t) pma->cbSize);
|
||
|
|
||
|
// Free tracking block
|
||
|
IMalloc *pMalloc = NULL;
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#ifdef MULTIHEAP
|
||
|
pMalloc = &g_smAllocator;
|
||
|
#else
|
||
|
if ( FAILED(DfCreateSharedAllocator ( &pMalloc )) )
|
||
|
pMalloc = NULL;
|
||
|
#endif // MULTIHEAP
|
||
|
#else
|
||
|
if (FAILED(DfGetScode(CoGetMalloc(MEMCTX_SHARED, &pMalloc))))
|
||
|
pMalloc = NULL;
|
||
|
#endif
|
||
|
|
||
|
if (pMalloc != NULL)
|
||
|
{
|
||
|
memset(pma, OLDMEM, sizeof(CMemAlloc));
|
||
|
pMalloc->Free(pma);
|
||
|
pMalloc->Release();
|
||
|
}
|
||
|
else
|
||
|
olAssert(!aMsg("Unable to get shared allocator\n"));
|
||
|
|
||
|
TaskMemFree(pv);
|
||
|
}
|
||
|
|
||
|
#endif // DBG==1 && !defined(MULTIHEAP)
|
||
|
|
||
|
#if !defined(WIN32)
|
||
|
|
||
|
#ifdef CODESEGMENTS
|
||
|
#pragma code_seg(SEG_TaskMemAlloc)
|
||
|
#endif
|
||
|
|
||
|
void *TaskMemAlloc(ULONG ulcb)
|
||
|
{
|
||
|
void FAR* pv = NULL;
|
||
|
IMalloc FAR* pMalloc;
|
||
|
|
||
|
if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc))))
|
||
|
{
|
||
|
pv = pMalloc->Alloc(ulcb);
|
||
|
pMalloc->Release();
|
||
|
}
|
||
|
|
||
|
return(pv);
|
||
|
}
|
||
|
|
||
|
#ifdef CODESEGMENTS
|
||
|
#pragma code_seg(SEG_TaskMemFree)
|
||
|
#endif
|
||
|
|
||
|
void TaskMemFree(void *pv)
|
||
|
{
|
||
|
IMalloc FAR* pMalloc;
|
||
|
if (SUCCEEDED(GetScode(CoGetMalloc(MEMCTX_TASK, &pMalloc))))
|
||
|
{
|
||
|
pMalloc->Free(pv);
|
||
|
pMalloc->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif // !defined(WIN32)
|
||
|
|
||
|
#if DBG == 1 && WIN32 == 0
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: operator new
|
||
|
//
|
||
|
// Synopsis: Global new
|
||
|
//
|
||
|
// Effects: Asserts
|
||
|
//
|
||
|
// Arguments: [size] -- count of bytes
|
||
|
//
|
||
|
// History: 26-May-93 AlexT Created
|
||
|
//
|
||
|
// Notes: None of our code should use global new
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void * _CRTAPI1 operator new(size_t size)
|
||
|
{
|
||
|
olAssert(!aMsg("global new called"));
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: operator delete
|
||
|
//
|
||
|
// Synopsis: Global delete
|
||
|
//
|
||
|
// Effects: Asserts
|
||
|
//
|
||
|
// Arguments: [pv] -- memory address
|
||
|
//
|
||
|
// History: 26-May-93 AlexT Created
|
||
|
//
|
||
|
// Notes: None of our code should use global delete
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
void _CRTAPI1 operator delete(void *pv)
|
||
|
{
|
||
|
olAssert(!aMsg("Global delete called"));
|
||
|
}
|
||
|
|
||
|
#endif // DBG == 1 && WIN32 == 0
|