📄 heapman.c
字号:
/*****************************************************************************
Name : HEAPMAN.C
Title : Shared memory heap manager.
C Author : Dave Roberts
Created : 24 / 10 / 03
Copyright : 2002-2003 by Imagination Technologies Limited.
All rights reserved. No part of this software, either
material or conceptual may be copied or distributed,
transmitted, transcribed, stored in a retrieval system
or translated into any human or computer language in any
form by any means, electronic, mechanical, manual or
other-wise, or disclosed to third parties without the
express written permission of Imagination Technologies
Limited, Unit 8, HomePark Industrial Estate,
King's Langley, Hertfordshire, WD4 8LZ, U.K.
Description : heap manager for shared memory
Program Type : 32-bit DLL
Modifications :
Initial revision
*****************************************************************************/
#include <windows.h>
#include "img_types.h"
#include "services_headers.h"
#include "heapman.h"
#define DPF_NEWLINE
#define DBG_BREAK
/*************************************************************************
Structure of the blocks in the heap.
Block header : Structure that holds info about the block
Aligment buffer : Buffer used to pad out the header so linear address
returned to the caller is aligned
Header size : Is the size of the Block header + Alignment buffer and
back pointer
Back pointer : Use so that from the calls linear address we can
locate the start of the block
7
--> ----------------------------- . <- start of block linear address
| | Block header | /|\
| | (GLOB_HEAP) | |
| ----------------------------- |
| | | |
| \ / |
| . Alignment buffer . Header size
| / \ |
| | | |
| ----------------------------- |
|-- | Back pointer | \|/
----------------------------- . <- aligned linear address passed back to called
| |
| |
. .
. .
. .
The alignment buffers size is depenant on the required alignment,
the size of the GLOB_HEAP struct, the size of the back pointer and
the linear address of the start of the block.
***************************************************************************/
/*****************************************************************************
Function prototypes
*****************************************************************************/
IMG_VOID CheckHostHeaps(IMG_VOID);
IMG_PVOID HostNonPageablePageAlloc(IMG_UINT32 ui32NumPages, IMG_PVOID pvHeapContext, IMG_PVOID *ppvAllocContext, IMG_PVOID pvLinAddr);
IMG_VOID HostNonPageablePageFree(IMG_PVOID pvLinAddr, IMG_UINT32 ui32NumPages, IMG_PVOID pvHeapContext, IMG_PVOID pvAllocContext);
IMG_VOID NonCachedHeapCheck(PHOST_HEAP psHeap);
IMG_PVOID AllocFromExistingBlocks(HOST_HEAP *psHostHeap, IMG_UINT32 ui32Size, IMG_UINT32 ui32Alignment, IMG_UINT32 ui32OwnerAddr);
IMG_VOID CalcBufAlignment(PGLOB_HEAP psStartOfBlock, IMG_UINT32 ui32Alignment, IMG_UINT32 *pui32HeaderSize);
IMG_BOOL IsValidAlignment(IMG_UINT32 ui32Value);
__inline IMG_VOID HeapAddBlockToFreeList(HOST_HEAP *psHostHeap, PGLOB_HEAP psNewBlock);
__inline IMG_VOID HeapRemoveBlockToFreeList(HOST_HEAP *psHostHeap, PGLOB_HEAP psBlock);
IMG_UINT32 CheckHeapFreeBlock(IMG_PVOID pvStart, IMG_UINT32 ui32Size);
IMG_VOID ProcessAllocCallbacks(IMG_BOOL bAlloc, IMG_PVOID pvAddr, IMG_UINT32 ui32Size);
IMG_BOOL AddBlockAllocCallback(PFN_HEAPBLOCK_CALLBACK pfnFunc);
IMG_VOID RemoveBlockAllocCallback(PFN_HEAPBLOCK_CALLBACK pfnFunc);
IMG_VOID DoBlockCallbacksForHeap(PHOST_HEAP psHeap);
/*****************************************************************************
Global data
*****************************************************************************/
IMG_UINT32 ui32HeapCheckLevel=HOST_HEAP_DBGCHK_NONE;
IMG_UINT32 aui32ValidAlignments[]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 0};
PFN_HEAPBLOCK_CALLBACK sfnBlockAllocCallbacks[MAX_ALLOC_CALLBACKS]={(PFN_HEAPBLOCK_CALLBACK)NULL, (PFN_HEAPBLOCK_CALLBACK)NULL, (PFN_HEAPBLOCK_CALLBACK)NULL, (PFN_HEAPBLOCK_CALLBACK)NULL, (PFN_HEAPBLOCK_CALLBACK)NULL};
typedef struct
{
DWORD dwDbgAllocFlags;
DWORD dwFailAllocType;
DWORD dwHostAllocDbgLevel;
DWORD dwFBAllocDbgLevel;
DWORD dwFailAllocThreshold;
DWORD dwFailAllocRndSeed;
DWORD dwFailAllocRndPercent;
DWORD dwFailAllocEveryXAllocs;
DWORD dwAllocCount;
}DBG_ALLOCS, *PDBG_ALLOCS;
#define FAILALLOC_TYPE_NONE 0
#define FAILALLOC_TYPE_RANDOM 1
#define FAILALLOC_TYPE_EVERYX 2
#define DBGALLOC_INT3ONFAIL 0x1000
DBG_ALLOCS sGlbDbgAllocs;
/*****************************************************************************
FUNCTION : InitHeapman
PURPOSE : initialises the shared system memory heap
PARAMETERS : ppsHeap - heap structure
RETURNS : PVRSRV_ERROR
*****************************************************************************/
PVRSRV_ERROR InitHeapman(HOST_HEAP **ppsHeap)
{
IMG_UINT32 i;
HOST_HEAP *psHeap;
psHeap = HostPageableByteAlloc(sizeof(HOST_HEAP));
if (psHeap == NULL)
{
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
/* we also need to reserve a shared linear address range (>2Mb) */
psHeap->pvLinearBase = VirtualAlloc(NULL, SYS_MAX_PAGES * HOST_PAGESIZE(), MEM_RESERVE, PAGE_NOACCESS);
if (psHeap->pvLinearBase == NULL)
{
HostPageableByteFree(psHeap);
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
/* setup heap structure */
psHeap->ui32Flags = HEAP_ALLOC_CANT_SPLIT_PAGE;
psHeap->ui32AllocsInHeap=0;
psHeap->psHeapStart=(PGLOB_HEAP)NULL;
psHeap->psFreeHeapStart=(PGLOB_HEAP)NULL;
psHeap->ui32MaxHeapSizeInPages=SYS_MAX_PAGES;
psHeap->ui32CurHeapSizeInPages=0;
psHeap->ui32ExpandSizeInPages=8;
psHeap->ui32MaxSingleHeapAllocInBytes=HOST_PAGESIZE();
psHeap->bAllowLargeSingleAllocs=TRUE;
psHeap->pfnHostAllocPage = HostNonPageablePageAlloc;
psHeap->pfnHostFreePage = HostNonPageablePageFree;
/* allocate a page block state table */
psHeap->psPageState = HostPageableByteAlloc (psHeap->ui32MaxHeapSizeInPages * sizeof(PAGE_STATE));
if (psHeap->psPageState == NULL)
{
return PVRSRV_ERROR_OUT_OF_MEMORY;
}
/* initialise the state block */
for (i=0; i<psHeap->ui32MaxHeapSizeInPages; i++)
{
psHeap->psPageState[i].bPageCommitted = IMG_FALSE;
psHeap->psPageState[i].pvLinearAddr = (IMG_PVOID)((IMG_UINT32)psHeap->pvLinearBase + (i * HOST_PAGESIZE()));
}
/* copy back */
*ppsHeap = psHeap;
return PVRSRV_OK;
}
/*****************************************************************************
FUNCTION : DeInitHeapman
PURPOSE : deinitialises the shared system memory heap
PARAMETERS : psHeap - heap structure
RETURNS : PVRSRV_ERROR
*****************************************************************************/
PVRSRV_ERROR DeInitHeapman(HOST_HEAP *psHeap)
{
HostPageableByteFree (psHeap->psPageState);
/* we also need to reserve a shared linear address range (>2Mb) */
if (VirtualFree(psHeap->pvLinearBase, SYS_MAX_PAGES * HOST_PAGESIZE(), MEM_RELEASE) == 0)
{
PVR_DPF((PVR_DBG_ERROR,"VirtualFree : failed to free reserved sysmem linear range\n"));
}
HostPageableByteFree(psHeap);
return PVRSRV_OK;
}
#if 0 /*! @todo */
/**************************************************************************
* Function Name : ReadDbgAllocSettings
* Inputs : None
* Outputs : None
* Returns : None
* Globals Used : sGlbDbgAllocs - we init this structure
* Description : Reads info out of the registry and inits the sGlbDbgAllocs structure
**************************************************************************/
void ReadDbgAllocSettings(DWORD dwDevCookie)
{
sGlbDbgAllocs.dwAllocCount=0;
/* Read the debug alloc flags */
if (HostReadRegistryDWORDFromString(dwDevCookie, "pmxkern", "DbgAllocFlags", &sGlbDbgAllocs.dwDbgAllocFlags) != PVRSRV_OK)
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Debug alloc flags not present assume 0");
sGlbDbgAllocs.dwDbgAllocFlags=0;
}
else
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Debug alloc flags are 0x%lx", sGlbDbgAllocs.dwDbgAllocFlags);
}
/* Get fail alloc type */
sGlbDbgAllocs.dwFailAllocType=sGlbDbgAllocs.dwDbgAllocFlags & DBGALLOC_FAILALLOC_TYPE_MASK;
switch (sGlbDbgAllocs.dwFailAllocType)
{
case FAILALLOC_TYPE_NONE :
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Alloc failing is disabled");
break;
case FAILALLOC_TYPE_RANDOM :
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Random alloc failing is enabled");
/* Get the alloc fail percentage */
if (HostReadRegistryDWORDFromString(dwDevCookie, "pmxkern", "FAllocRndPercent", &sGlbDbgAllocs.dwFailAllocRndPercent) != PVRSRV_OK)
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : No failing percent was specified, using probability of 50 in 10000");
sGlbDbgAllocs.dwFailAllocRndPercent=50;
}
else
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Will fail allocs using probability of %ld in 1000", sGlbDbgAllocs.dwFailAllocRndPercent);
}
/* Check for seed to use */
if (HostReadRegistryDWORDFromString(dwDevCookie, "pmxkern", "FAllocRndSeed", &sGlbDbgAllocs.dwFailAllocRndSeed) != PVRSRV_OK)
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : No random seed given will use RDTSC for seed");
}
else
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Will use ramdom seed of 0x%lx", sGlbDbgAllocs.dwFailAllocRndSeed);
dwGlbRandomSeed=sGlbDbgAllocs.dwFailAllocRndSeed;
}
/* Force the seed to be used and then store the seed away */
GetRandNum();
sGlbDbgAllocs.dwFailAllocRndSeed=dwGlbRandomSeed;
break;
case FAILALLOC_TYPE_EVERYX :
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Failing allocs every X allocs is enabled");
/* Get the failing frequence */
if (HostReadRegistryDWORDFromString(dwDevCookie, "pmxkern", "FAllocEveryXAllocs", &sGlbDbgAllocs.dwFailAllocEveryXAllocs) != PVRSRV_OK)
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : No failing frequence was specified, using 1 in every 1000 allocs");
sGlbDbgAllocs.dwFailAllocEveryXAllocs=1000;
}
else
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : KM will fail 1 in every %ld allocs", sGlbDbgAllocs.dwFailAllocEveryXAllocs);
}
break;
default :
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Alloc fail type %ld unknown", sGlbDbgAllocs.dwFailAllocType);
sGlbDbgAllocs.dwFailAllocType=FAILALLOC_TYPE_NONE;
}
/* Find the alloc threshold */
if (sGlbDbgAllocs.dwFailAllocType != FAILALLOC_TYPE_NONE)
{
if (HostReadRegistryDWORDFromString(dwDevCookie, "pmxkern", "FAllocThreshold", &sGlbDbgAllocs.dwFailAllocThreshold) != PVRSRV_OK)
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : No alloc threshold given, use 250");
sGlbDbgAllocs.dwFailAllocThreshold=250;
}
else
{
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : An alloc threshold of %ld was given", sGlbDbgAllocs.dwFailAllocThreshold);
}
}
/* Get host heap alloc debug checking level */
sGlbDbgAllocs.dwHostAllocDbgLevel=(sGlbDbgAllocs.dwDbgAllocFlags & DBGALLOC_HOST_DBGLEV_MASK) >> DBGALLOC_HOST_DBGLEV_SHIFT;
dwHeapCheckLevel=sGlbDbgAllocs.dwHostAllocDbgLevel;
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : Host heap debug level is %ld", sGlbDbgAllocs.dwHostAllocDbgLevel);
/* Get FB heap alloc debug checking level */
sGlbDbgAllocs.dwFBAllocDbgLevel=(sGlbDbgAllocs.dwDbgAllocFlags & DBGALLOC_FB_DBGLEV_MASK) >> DBGALLOC_FB_DBGLEV_SHIFT;
DPFLX(DBG_ALLOC_CHK, "ReadDbgAllocSettings : FB heap debug level is %ld", sGlbDbgAllocs.dwFBAllocDbgLevel);
return;
}
/**************************************************************************
* Function Name : FailAlloc
* Inputs : None
* Outputs : None
* Returns : TRUE if we should fail this alloc and FALSE if we should allow it
* Globals Used : sGlbDbgAllocs structure
* Description : Check to see if we should fail this alloc
**************************************************************************/
BOOL FailAlloc(void)
{
BOOL bFail=FALSE;
DWORD dwGlbRandomSeed=0;
/* Inc alloc count */
sGlbDbgAllocs.dwAllocCount++;
/* Check if threshold has been reached */
if (sGlbDbgAllocs.dwAllocCount > sGlbDbgAllocs.dwFailAllocThreshold)
{
/* Check what type of alloc failing we want */
switch (sGlbDbgAllocs.dwFailAllocType)
{
case FAILALLOC_TYPE_NONE :
break;
case FAILALLOC_TYPE_RANDOM :
{
WORD wRnd=100;
/* Check if we should fail */
if (wRnd <= sGlbDbgAllocs.dwFailAllocRndPercent)
{
bFail=TRUE;
PVR_DPF((PVR_DBG_MESSAGE, "FailAlloc : Just about to fail this alloc, random seed was 0x%lx, fail rate %ld in 10000", dwGlbRandomSeed, sGlbDbgAllocs.dwFailAllocRndPercent));
}
break;
}
case FAILALLOC_TYPE_EVERYX :
if ((sGlbDbgAllocs.dwAllocCount % sGlbDbgAllocs.dwFailAllocEveryXAllocs) == 0)
{
bFail=TRUE;
PVR_DPF((PVR_DBG_MESSAGE, "FailAlloc : Just about to fail this alloc, we fail every %ldth alloc", sGlbDbgAllocs.dwFailAllocEveryXAllocs));
}
break;
default :
{
PVR_DPF((PVR_DBG_MESSAGE, "FailAlloc : should never have an un supported type (%lx)", sGlbDbgAllocs.dwFailAllocType));
DBG_BREAK;
}
}
}
if (bFail==TRUE)
{
PVR_DPF((PVR_DBG_MESSAGE, "FailAlloc : We are failing this alloc, alloc count is %ld", sGlbDbgAllocs.dwAllocCount));
if (sGlbDbgAllocs.dwDbgAllocFlags & DBGALLOC_INT3ONFAIL)
{
DBG_BREAK;
}
}
return bFail;
}
#endif
/*!
******************************************************************************
@Function HostAllocMem
@Description Allocates host memory from one of the host heaps
@Input ui32Flags - flags for allocation, this includes the heap to be
used for this allocation (PVRSRV_HOST_xxx_HEAP)
@Input ui32Size - number of bytes to alloc
@Input ui32OwnerAddr - addr of caller
@Output ppvLinAddr - pointer to variable that receives the linear
address of allocated memory
@Return PVRSRV_OK on success else PVRSRV_ERROR_OUT_OF_MEMORY
******************************************************************************/
PVRSRV_ERROR HostAllocMem(IMG_UINT32 ui32Flags, IMG_UINT32 ui32Size, IMG_PVOID *ppvLinAddr, IMG_UINT32 ui32OwnerAddr)
{
IMG_PVOID pvLinAddr=NULL;
IMG_UINT32 ui32HeapIndex=ui32Flags & PVRSRV_HOST_HEAP_MASK;
SYS_DATA *psSysData;
PVRSRV_ERROR eRetCode=PVRSRV_OK;
IMG_BOOL bAllocDone=FALSE;
ENV_DATA *psEnvData;
if (SysAcquireData(&psSysData) != PVRSRV_OK)
{
return 0;
}
psEnvData = (ENV_DATA*)psSysData->pvEnvSpecificData;
#if 0 /*! @todo implement on DEBUG */
/* Check we should fail this alloc */
if (FailAlloc() == TRUE)
{
PVR_DPF((PVR_DBG_ERROR, "MemHeapAlloc : We have been asked to fail this alloc"));
return (PVRSRV_ERROR_OUT_OF_MEMORY);
}
#endif
#if 0 /*! @todo implement on DEBUG && !defined(NO_ALLOC_TRACKING)*/
/* Get calls return addr if not already given */
if (ui32OwnerAddr == 0)
{
GetReturnAddress(ui32OwnerAddr);
}
#endif /* #if defined(DEBUG) && !defined(NO_ALLOC_TRACKING) */
PVR_DPF((PVR_DBG_MESSAGE, "HostAllocMem() size %lu (%lu Kb), flags 0x%lx, caller 0x%lx", ui32Size, ui32Size/1024, ui32Flags, ui32OwnerAddr));
#ifdef DEBUG
/*Check heap*/
CheckHostHeaps();
#endif
/*Set lin addr to NULL*/
*ppvLinAddr=NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -