📄 heapman.c
字号:
{
HostMemSet(pvLinAddr, (IMG_UINT8)DBG_MEMORY_INITIALIZER, ui32Size);
}
#endif /*DEBUG*/
return(pvLinAddr);
}
/**************************************************************************
* Function Name : AllocFromExistingBlocks()
* Inputs : psHostHeap - pointer the host heap
* ui32Size - size of block to alloc
* ui32Alignment - alignment required for this allocation
* must be a power of two
* ui32OwnerAddr - addr of allocater
* Outputs : None
* Returns : Linear address of buffer alloced on success else NULL
* Globals Used : None
* Description : Walk through the heap looking for free blocks big enough
* for this alloc
**************************************************************************/
IMG_PVOID AllocFromExistingBlocks(HOST_HEAP *psHostHeap, IMG_UINT32 ui32Size, IMG_UINT32 ui32Alignment, IMG_UINT32 ui32OwnerAddr)
{
PGLOB_HEAP psCurHeapBlock;
PGLOB_HEAP psNewHeapBlock;
IMG_UINT32 ui32HeaderSize;
IMG_PVOID pvCallerBufStart;
if (ui32OwnerAddr);
psCurHeapBlock = psHostHeap->psFreeHeapStart;
/*Look at each block*/
while (psCurHeapBlock != NULL)
{
/*Check if block is already used*/
if ((psCurHeapBlock->ui32Flags & GHEAP_BLOCK_ALLOCATED) == 0)
{
/* Quick check to if block size is anywhere near big enough */
if (psCurHeapBlock->ui32BlockSize > (ui32Size + sizeof(GLOB_HEAP)))
{
/*Check if this block will be big enough*/
CalcBufAlignment(psCurHeapBlock, ui32Alignment, &ui32HeaderSize);
/* Check if alloc is allowed to split page */
if ((psHostHeap->ui32Flags & HEAP_ALLOC_CANT_SPLIT_PAGE) != 0)
{
PBYTE pbyBufFirstByte=(PBYTE)psCurHeapBlock + ui32HeaderSize;
PBYTE pbyBufLastByte=pbyBufFirstByte + ui32Size - 1;
if (((IMG_UINT32)pbyBufFirstByte & ~0xfff) != ((IMG_UINT32)pbyBufLastByte & ~0xfff))
{
/* Ensure that alloc comes from same page */
ui32HeaderSize+=0x1000 - ((IMG_UINT32)pbyBufFirstByte & 0xfff);
}
}
if ((ui32HeaderSize + ui32Size) <= psCurHeapBlock->ui32BlockSize)
{
/*Setup block header*/
psCurHeapBlock->ui32Flags |= GHEAP_BLOCK_ALLOCATED;
pvCallerBufStart=(BYTE *)psCurHeapBlock + ui32HeaderSize;
*((IMG_UINT32 *)pvCallerBufStart-1)=(IMG_UINT32)psCurHeapBlock;
#if defined(DEBUG) && !defined(NO_ALLOC_TRACKING)
psCurHeapBlock->pfnOwner=(POWNER_FN)ui32OwnerAddr;
#endif /* #if defined(DEBUG) && !defined(NO_ALLOC_TRACKING) */
/* Inc count of allocations in the heap */
psHostHeap->ui32AllocsInHeap++;
/* Remove block from free list */
HeapRemoveBlockToFreeList(psHostHeap, psCurHeapBlock);
/*
Exact size, don't need to allocate new heap struct.
*/
if ((ui32HeaderSize + ui32Size) == psCurHeapBlock->ui32BlockSize)
{
return(pvCallerBufStart);
}
/*
Not exact size, if we have space for another heap structure
in the remains of the block set it up as a new one, otherwise
leave orignal block at its full size.
*/
if ((psCurHeapBlock->ui32BlockSize - (ui32HeaderSize + ui32Size)) > (sizeof(GLOB_HEAP) + sizeof(IMG_PVOID)))
{
psNewHeapBlock=(PGLOB_HEAP)((PBYTE)psCurHeapBlock + (ui32HeaderSize + ui32Size));
psNewHeapBlock->ui32Signiture=HOST_HEAP_SIGNITURE;
psNewHeapBlock->ui32Flags = psCurHeapBlock->ui32Flags & ~(GHEAP_BLOCK_ALLOCATED | GHEAP_BLOCK_HEAD);
psNewHeapBlock->ui32BlockSize = psCurHeapBlock->ui32BlockSize - (ui32HeaderSize + ui32Size);
psNewHeapBlock->psHeap=psHostHeap;
psCurHeapBlock->ui32BlockSize = (ui32HeaderSize + ui32Size);
/*
Insert new block into list.
*/
if (psCurHeapBlock->psNext != NULL)
{
psCurHeapBlock->psNext->psPrev = psNewHeapBlock;
}
psNewHeapBlock->psNext = psCurHeapBlock->psNext;
psNewHeapBlock->psPrev = psCurHeapBlock;
psCurHeapBlock->psNext = psNewHeapBlock;
/* Insert new block at front of free list */
HeapAddBlockToFreeList(psHostHeap, psNewHeapBlock);
}
/* Chech does not split page if is should not */
PVR_ASSERT(((psHostHeap->ui32Flags & HEAP_ALLOC_CANT_SPLIT_PAGE) == 0) || ((IMG_UINT32)(pvCallerBufStart) & ~0xfff) == (((IMG_UINT32)(pvCallerBufStart)+ui32Size-1) & ~0xfff));
/* And return pointer to allocate memory. */
return(pvCallerBufStart);
}/* End check if this block will be big enough*/
}/* End of quick check of block size */
}/* End checking if block is already used*/
/*Onto next heap block*/
psCurHeapBlock = psCurHeapBlock->psNextFree;
}/*End looking at each block*/
return(NULL);
}
/**************************************************************************
* Function Name : MemHeapFree
* Inputs : psHostHeap - pointer to heap to free from
* pvMemPtr - linear address of buffer to free
* pvHeapContext - context pointer passed onto the page free
* routine
* Outputs : None
* Returns : TRUE on success, FALSE on failure
* Globals Used : None
* Description : Frees a block that was alloced using MemHeapAlloc()
**************************************************************************/
IMG_BOOL MemHeapFree(IMG_PVOID pvMemPtr, IMG_PVOID pvHeapContext)
{
PGLOB_HEAP psHeapBlock;
PGLOB_HEAP psNext;
PGLOB_HEAP psPrev;
HOST_HEAP *psHostHeap;
/*Check for NULL*/
if (pvMemPtr == NULL)
{
PVR_DPF((PVR_DBG_ERROR, "HostFreeMem() Caller tried to free NULL!!!\n"));
return FALSE;
}
/*Go back from memory pointer to heap block.*/
psHeapBlock = (PGLOB_HEAP) *((IMG_UINT32 *)pvMemPtr - 1);
psHostHeap=psHeapBlock->psHeap;
/*Check this is a valid block*/
if (psHeapBlock == NULL || psHeapBlock->ui32Signiture != HOST_HEAP_SIGNITURE)
{
PVR_DPF((PVR_DBG_ERROR, "HostFreeMem() Caller tried to free a block (0x%lx) that is not valid!!!\n", pvMemPtr));
DBG_BREAK;
return FALSE;
}
/* Check next block sign */
PVR_ASSERT(psHeapBlock->psNext == NULL || psHeapBlock->psNext->ui32Signiture == HOST_HEAP_SIGNITURE);
/*Check this is a allocated block*/
if ((psHeapBlock->ui32Flags & GHEAP_BLOCK_ALLOCATED) == 0)
{
PVR_DPF((PVR_DBG_ERROR, "HostFreeMem() Caller tried to free block (0x%lx) has not been allocated!!!\n", pvMemPtr));
DBG_BREAK;
return FALSE;
}
/*Indicate that this block is now free*/
psHeapBlock->ui32Flags &= ~GHEAP_BLOCK_ALLOCATED;
#if defined(DEBUG) && !defined(NO_ALLOC_TRACKING)
psHeapBlock->pfnOwner=(POWNER_FN)NULL;
#endif /* #if defined(DEBUG) && !defined(NO_ALLOC_TRACKING) */
/*Free memory if it was a single allocation*/
if (psHeapBlock->ui32Flags & GHEAP_SINGLE)
{
/*Single allocation heap, just need to free pages.*/
ProcessAllocCallbacks(FALSE, psHeapBlock, psHeapBlock->ui32BlockSize / HOST_PAGESIZE());
ReleasePages(psHeapBlock->psPageState, psHeapBlock->ui32BlockSize / HOST_PAGESIZE());
(psHostHeap->pfnHostFreePage)((IMG_PVOID)psHeapBlock, psHeapBlock->ui32BlockSize / HOST_PAGESIZE(), pvHeapContext, ((PGLOB_HEAP_HEAD)psHeapBlock)->pvBlkAllocContext);
return TRUE;
}
/* Decrease count of allocations in the heap */
psHostHeap->ui32AllocsInHeap--;
/*
Traverse forward through list contatenating free blocks until we either,
* come to the end of the list,
* come to an allocated block,
* come to a new page allocation block (defined by GHEAP_BLOCK_HEAD)
*/
psNext = psHeapBlock->psNext;
while (
(psNext != NULL) &&
!(psNext->ui32Flags & GHEAP_BLOCK_ALLOCATED) &&
!(psNext->ui32Flags & GHEAP_BLOCK_HEAD)
)
{
psHeapBlock->ui32BlockSize += psNext->ui32BlockSize;
/*
Remove block from list.
*/
if (psNext->psNext != NULL)
{
psNext->psNext->psPrev = psHeapBlock;
}
psHeapBlock->psNext = psNext->psNext;
/* Remove block from free list */
HeapRemoveBlockToFreeList(psHostHeap, psNext);
/*
To be safe zero concatenated blocks link pointers.
*/
psNext->psNext = (PGLOB_HEAP) 0;
psNext->psPrev = (PGLOB_HEAP) 0;
/*
Move to next block.
*/
psNext = psHeapBlock->psNext;
}
/*
Same again but traverse back from block...
*/
psPrev = psHeapBlock->psPrev;
while (
(psPrev != NULL) &&
!(psPrev->ui32Flags & GHEAP_BLOCK_ALLOCATED) &&
!(psHeapBlock->ui32Flags & GHEAP_BLOCK_HEAD)
)
{
psNext = psHeapBlock;
psHeapBlock = psPrev;
psHeapBlock->ui32BlockSize += psNext->ui32BlockSize;
/*
Remove block from list.
*/
if (psNext->psNext != NULL)
{
psNext->psNext->psPrev = psHeapBlock;
}
psHeapBlock->psNext = psNext->psNext;
/* Remove block from free list */
HeapRemoveBlockToFreeList(psHostHeap, psHeapBlock);
/*
Move to next block.
*/
psPrev = psHeapBlock->psPrev;
/*
To be safe zero concatenated blocks link pointers.
*/
psNext->psNext = (PGLOB_HEAP) 0;
psNext->psPrev = (PGLOB_HEAP) 0;
}
#ifdef DEBUG
/* On a free set memory to known state */
if ((psHeapBlock->ui32Flags & GHEAP_BLOCK_HEAD) == 0)
{
HostMemSet((IMG_PVOID)(psHeapBlock+1), (IMG_UINT8)DBG_MEMORY_DEALLOC_INITIALIZER, psHeapBlock->ui32BlockSize - sizeof(GLOB_HEAP));
}
else
{
HostMemSet((IMG_PVOID)(((PGLOB_HEAP_HEAD)psHeapBlock)+1), (IMG_UINT8)DBG_MEMORY_DEALLOC_INITIALIZER, psHeapBlock->ui32BlockSize - sizeof(GLOB_HEAP_HEAD));
}
#endif /* #ifdef DEBUG */
/*
If this block is a block head and it either points to another block
head or the end of the heap list, remove from heap list and free the
pages allocated within it.
*/
if (psHeapBlock->ui32Flags & GHEAP_BLOCK_HEAD)
{
if (psHeapBlock->psNext == NULL)
{
if (psHeapBlock->psPrev == NULL)
{
/*This is heap head, so heap will be empty*/
psHostHeap->psHeapStart=(PGLOB_HEAP)NULL;
}
else
{
psHeapBlock->psPrev->psNext = (PGLOB_HEAP)NULL;
}
/*Free allocated pages*/
ProcessAllocCallbacks(FALSE, psHeapBlock, psHostHeap->ui32ExpandSizeInPages * HOST_PAGESIZE());
ReleasePages(psHeapBlock->psPageState, psHostHeap->ui32ExpandSizeInPages);
(psHostHeap->pfnHostFreePage)((IMG_PVOID)psHeapBlock, psHostHeap->ui32ExpandSizeInPages, pvHeapContext, ((PGLOB_HEAP_HEAD)psHeapBlock)->pvBlkAllocContext);
psHostHeap->ui32CurHeapSizeInPages-=psHostHeap->ui32ExpandSizeInPages;
psHeapBlock=(PGLOB_HEAP)NULL;
}
else
{
if (psHeapBlock->psNext->ui32Flags & GHEAP_BLOCK_HEAD)
{
if (psHeapBlock->psPrev == NULL)
{
/*Is heap head, next block becomes head*/
psHostHeap->psHeapStart=psHeapBlock->psNext;
}
else
{
psHeapBlock->psPrev->psNext = psHeapBlock->psNext;
}
psHeapBlock->psNext->psPrev = psHeapBlock->psPrev;
/*Free allocated pages.*/
ProcessAllocCallbacks(FALSE, psHeapBlock, psHostHeap->ui32ExpandSizeInPages * HOST_PAGESIZE());
ReleasePages(psHeapBlock->psPageState, psHostHeap->ui32ExpandSizeInPages);
(psHostHeap->pfnHostFreePage)((IMG_PVOID)psHeapBlock, psHostHeap->ui32ExpandSizeInPages, pvHeapContext, ((PGLOB_HEAP_HEAD)psHeapBlock)->pvBlkAllocContext);
psHostHeap->ui32CurHeapSizeInPages-=psHostHeap->ui32ExpandSizeInPages;
psHeapBlock=(PGLOB_HEAP)NULL;
}
}
}
/* If we did not free that block of memory add it so the free list */
if (psHeapBlock != NULL)
{
HeapAddBlockToFreeList(psHostHeap, psHeapBlock);
}
return TRUE;
}
/**************************************************************************
* Function Name : CalcBufAlignment
* Inputs : pvStartOfBlock - linear address of the start of block
* ui32Alignment - required alignment of buffer
* Outputs : pui32HeaderSize - pointer to varable that will receive the
* header size for the given block
* Returns : None
* Globals Used : None
* Description : Given the start of the block and required alignment this
* routine will calculate the header size and alignment
* buffer size to that the address passed back to the caller
* is aligned correctly
**************************************************************************/
IMG_VOID CalcBufAlignment(PGLOB_HEAP psStartOfBlock, IMG_UINT32 ui32Alignment, IMG_UINT32 *pui32HeaderSize)
{
IMG_PVOID pvEndOfHeader;
IMG_UINT32 ui32SizeOfStruct=sizeof(GLOB_HEAP);
if ((psStartOfBlock->ui32Flags & GHEAP_BLOCK_HEAD) != 0)
{
ui32SizeOfStruct=sizeof(GLOB_HEAP_HEAD);
}
/*Calc end of header*/
pvEndOfHeader=(IMG_PVOID)((IMG_UINT32)((BYTE *)psStartOfBlock + ui32SizeOfStruct + sizeof(IMG_PVOID) + ui32Alignment - 1) & ~(ui32Alignment-1));
/*Calc header size and aligmnent buffer size*/
*pui32HeaderSize=(BYTE *)pvEndOfHeader - (BYTE *)psStartOfBlock;
PVR_ASSERT((*pui32HeaderSize - (ui32SizeOfStruct + sizeof(IMG_PVOID))) < ui32Alignment);
return;
}
/**************************************************************************
* Function Name : IsValidAlignment
* Inputs : ui32Value - the requested alignment
* Outputs : None
* Returns : TRUE if alignment is valid, else FALSE
* Globals Used : aui32ValidAlignments - read values from table
* Description : Check if the requested alignment is valid (has to be power
* of two) by looking for it in the valid alignments table
**************************************************************************/
IMG_BOOL IsValidAlignment(IMG_UINT32 ui32Value)
{
IMG_UINT32 *pui32ValidAlignment=aui32ValidAlignments;
while (*pui32ValidAlignment != 0)
{
if (ui32Value == *(pui32ValidAlignment++))
{
return TRUE;
}
}
return FALSE;
}
/**************************************************************************
* Function Name : HeapAddBlockToFreeList
* Inputs : psHostHeap - ptr to host heap this block belongs to
* psNewBlock - new block to be added to free list
* Outputs : None
* Returns : None
* Globals Used : None
* Description : Insert a block at the front of the free list
**************************************************************************/
__inline IMG_VOID HeapAddBlockToFreeList(HOST_HEAP *psHostHeap, PGLOB_HEAP psNewBlock)
{
/* Insert new block at front of free list */
psNewBlock->psNextFree=psHostHeap->psFreeHeapStart;
psNewBlock->psPrevFree=(PGLOB_HEAP)NULL;
if (psHostHeap->psFreeHeapStart != NULL)
{
psHostHeap->psFreeHeapStart->psPrevFree=psNewBlock;
}
psHostHeap->psFreeHeapStart=psNewBlock;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -