malloc.cpp

来自「firtext搜索引擎源码」· C++ 代码 · 共 618 行 · 第 1/2 页

CPP
618
字号
#include "com/comerror.h"
#include "com/Com.h"
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>
#include "com/linux/internal.h"

namespace firtex
{
	namespace com 
	{
		namespace internal 
		{
			class Malloc : public IMalloc 
			{
			public:
				Malloc();
				~Malloc();

				FX_STDMETHOD(QueryInterface)( firtex::com::FX_IID const& riid, void** ptr );
				FX_STDMETHOD_(uint32_t,AddRef)();
				FX_STDMETHOD_(uint32_t,Release)();
				FX_STDMETHOD_(void*,Alloc)(uint32_t);
				FX_STDMETHOD_(void*,Realloc)(void*,uint32_t);
				FX_STDMETHOD_(void,Free)(void*);
				FX_STDMETHOD_(uint32_t,GetSize)(void*);
				FX_STDMETHOD_(int16_t,DidAlloc)(void*);
				FX_STDMETHOD_(void,HeapMinimize)();

			public:
				IMallocSpy* pSpy;          /* the spy when active */
				uint32_t SpyedAllocationsLeft; /* number of spyed allocations left */
				bool SpyReleasePending;     /* FX_CoRevokeMallocSpy called with spyed allocations left*/
				void** SpyedBlocks;       /* root of the table */
				int SpyedBlockTableLength;  /* size of the table*/
			};
		}
	}
}

static firtex::com::internal::Malloc malloc32;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
	
/* resize the old table */
static firtex::com:: FX_HRESULT SetSpyedBlockTableLength ( int NewLength )
{
	void** NewSpyedBlocks = 0;

	if (! malloc32.SpyedBlocks ) {
		NewSpyedBlocks = (void**)malloc(NewLength*sizeof(void*));
		memset( NewSpyedBlocks, 0, NewLength*sizeof(void*) );
	}
	else {
		NewSpyedBlocks = (void**)realloc( malloc32.SpyedBlocks, NewLength*sizeof(void*));
		if ( NewLength > malloc32.SpyedBlockTableLength )
			memset( NewSpyedBlocks + malloc32.SpyedBlockTableLength, 0, (NewLength - malloc32.SpyedBlockTableLength)*sizeof(void*) );
	}

	if (NewSpyedBlocks) {
		malloc32.SpyedBlocks = NewSpyedBlocks;
		malloc32.SpyedBlockTableLength = NewLength;
		return FX_S_OK;
	}

	return FX_E_OUTOFMEMORY;
}

/* add a location to the table */
static firtex::com::FX_HRESULT AddMemoryLocation(void* pMem)
{
	/* allocate the table if not already allocated */
	if ( !malloc32.SpyedBlockTableLength ) {
		firtex::com::FX_HRESULT hr = SetSpyedBlockTableLength( 0x1000 );
		if ( FX_FAILED(hr) ) return hr;
	}

	/* find a free location */
	void** Current = malloc32.SpyedBlocks;
	while (*Current) {
		++Current;

	    if ( Current >= malloc32.SpyedBlocks + malloc32.SpyedBlockTableLength ) {
	    	/* no more space in table, grow it */
			firtex::com::FX_HRESULT hr = SetSpyedBlockTableLength( malloc32.SpyedBlockTableLength + 0x1000 );
			if ( FX_FAILED(hr) ) return hr;
	    }
	};

	/* put the location in our table */
	*Current = pMem;
	++malloc32.SpyedAllocationsLeft;
	return FX_S_OK;
}

static firtex::com::FX_HRESULT RemoveMemoryLocation(void* pMem)
{
	/* allocate the table if not already allocated */
	if ( !malloc32.SpyedBlockTableLength ) {
		firtex::com::FX_HRESULT hr = SetSpyedBlockTableLength( 0x1000 );
		if ( FX_FAILED(hr) ) return hr;
	}

	void** Current = malloc32.SpyedBlocks;

	/* find the location */
	while (*Current != pMem) {
		++Current;
	    if (Current >= malloc32.SpyedBlocks + malloc32.SpyedBlockTableLength)  
			return FX_E_FAIL;      /* not found  */
	}

	/* location found */
    --malloc32.SpyedAllocationsLeft;
	/*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
	*Current = NULL;
	return FX_S_OK;
}

firtex::com::internal::Malloc::Malloc()
{
	pSpy = 0;          
	SpyedAllocationsLeft = 0; 
	SpyReleasePending = false;
	
	SpyedBlocks = 0;
	SpyedBlockTableLength = 0;
}

firtex::com::internal::Malloc::~Malloc()
{
	free( SpyedBlocks );
}


/******************************************************************************
 *	IMalloc32_QueryInterface	[VTABLE]
 */
firtex::com::FX_HRESULT firtex::com::internal::Malloc::QueryInterface(FX_REFIID refiid,void** obj) 
{
	if ( !obj ) return FX_E_INVALIDARG;

	if ( FX_IsEqualIID(IUnknown::iid,refiid) ) {
		*obj = static_cast<IUnknown*>(this);
		return FX_S_OK;
	}
	else if ( FX_IsEqualIID(IMalloc::iid,refiid) ) {
		*obj = static_cast<IMalloc*>(this);
		return FX_S_OK;
	}
	return FX_E_NOINTERFACE;
}

/******************************************************************************
 *	IMalloc32_AddRefRelease		[VTABLE]
 */
uint32_t firtex::com::internal::Malloc::AddRef() {
	return 1;
}

uint32_t firtex::com::internal::Malloc::Release() {
	return 1;
}

/******************************************************************************
 *	IMalloc32_Alloc 		[VTABLE]
 */
void* firtex::com::internal::Malloc::Alloc(uint32_t cb) 
{
	if ( malloc32.pSpy ) {
	    uint32_t preAllocResult;

		::pthread_mutex_lock( &mutex );
	    
	    preAllocResult = malloc32.pSpy->PreAlloc(cb);
	    if ((cb != 0) && (preAllocResult == 0)) {
			/* PreAlloc can force Alloc to fail, but not if cb == 0 */
			::pthread_mutex_unlock( &mutex );
			return NULL;
	    }
	}
 	
	void* addr = malloc(cb);

	if ( malloc32.pSpy ) {
	    addr = malloc32.pSpy->PostAlloc(addr);
	    if (addr) AddMemoryLocation(addr);
		::pthread_mutex_unlock( &mutex );
	}

	return addr;
}

/******************************************************************************
 * IMalloc32_Realloc [VTABLE]
 */
void* firtex::com::internal::Malloc::Realloc(void* pv,uint32_t cb) 
{
	if ( malloc32.pSpy ) {
	    void* pRealMemory;
	    bool fSpyed;

		::pthread_mutex_lock( &mutex );

		FX_HRESULT hr = RemoveMemoryLocation(pv);
		fSpyed = FX_SUCCEEDED(hr);
		cb = malloc32.pSpy->PreRealloc( pv, cb, &pRealMemory, fSpyed);

	    /* check if can release the spy */
	    if( malloc32.SpyReleasePending && !malloc32.SpyedAllocationsLeft ) {
			malloc32.SpyReleasePending = false;
			malloc32.pSpy->Release();
			malloc32.pSpy = 0;
	    }

	    if (0==cb) {
	        /* PreRealloc can force Realloc to fail */
			::pthread_mutex_unlock( &mutex );
			return NULL;
	    }
	    pv = pRealMemory;
	}

	void* pNewMemory = 0;
    if (!pv) 
		pNewMemory = malloc(cb);
	else if (cb) 
		pNewMemory = realloc(pv,cb);
	else {
		free( pv );
	    pNewMemory = NULL;
	}

	if( malloc32.pSpy ) {
	    pNewMemory = malloc32.pSpy->PostRealloc(pNewMemory, -1);
	    if (pNewMemory) 
			AddMemoryLocation(pNewMemory);
		::pthread_mutex_unlock( &mutex );
	}

	return pNewMemory;
}

/******************************************************************************
 * IMalloc32_Free [VTABLE]
 */
void firtex::com::internal::Malloc::Free(void* pv) 
{
	bool fSpyed = false;

	if ( malloc32.pSpy ) {
		::pthread_mutex_lock( &mutex );
  		FX_HRESULT hr = RemoveMemoryLocation(pv);
		fSpyed = FX_SUCCEEDED(hr);

	    pv = malloc32.pSpy->PreFree(pv, fSpyed);
	}

	free( pv );

	if( malloc32.pSpy ) {
		malloc32.pSpy->PostFree( fSpyed );

	    /* check if can release the spy */
	    if(malloc32.SpyReleasePending && !malloc32.SpyedAllocationsLeft) {
			malloc32.SpyReleasePending = false;
			malloc32.pSpy->Release();
			malloc32.pSpy = NULL;
	    }

		::pthread_mutex_unlock( &mutex );
	}
}

/******************************************************************************
 * IMalloc32_GetSize [VTABLE]
 *
 * NOTES
 *  FIXME returns:
 *      win95:  size allocated (4 byte boundarys)
 *      win2k:  size originally requested !!! (allocated on 8 byte boundarys)
 */
uint32_t firtex::com::internal::Malloc::GetSize(void* pv) 
{
	bool fSpyed = false;

	if(malloc32.pSpy) {
		::pthread_mutex_lock( &mutex );
	    pv = malloc32.pSpy->PreGetSize(pv, fSpyed);
	}

	// oh, oh, what do we do here
	//cb = HeapSize(GetProcessHeap(),0,pv);
	//?uint32_t cb = msize( pv );
	uint32_t cb = 0;

	if( malloc32.pSpy ) {
	    cb = malloc32.pSpy->PostGetSize(cb, fSpyed);
		::pthread_mutex_unlock( &mutex );
	}

	return cb;
}

/******************************************************************************
 * IMalloc32_DidAlloc [VTABLE]
 */
int16_t firtex::com::internal::Malloc::DidAlloc(void* pv) 
{
	bool fSpyed = false;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?