/*---------------------------------------------------------------------------* Project: MEM library File: mem_unitHeap.c Programmers: Makoto Takano Copyright 2005 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ #include #include "heapCommoni.h" /* ======================================================================== Macro constants ======================================================================== */ // Minimum alignment value #define MIN_ALIGNMENT 4 /* ======================================================================== static functions ======================================================================== */ /* ------------------------------------------------------------------------ Memory Block List Operation ------------------------------------------------------------------------ */ /*---------------------------------------------------------------------------* Name: PopMBlock_ Description: Allocates the memory block from the top of the list. Arguments: link: pointer to list Returns: None. *---------------------------------------------------------------------------*/ static MEMiUntHeapMBlockHead* PopMBlock_( MEMiUntMBlockList* list ) { MEMiUntHeapMBlockHead* block = list->head; if ( block ) { list->head = block->pMBlkHdNext; } return block; } /*---------------------------------------------------------------------------* Name: PushMBlock_ Description: Adds memory block to top of list. Arguments: link: The list to add block: The memory block to add Returns: None. *---------------------------------------------------------------------------*/ static inline void PushMBlock_( MEMiUntMBlockList* list, MEMiUntHeapMBlockHead* block ) { block->pMBlkHdNext = list->head; list->head = block; } /*---------------------------------------------------------------------------* Name: GetUnitHeapHeadPtrFromHeapHead_ Description: Gets the unit heap header pointer from the heap header pointer. Arguments: pHeapHd: Pointer to the heap header. Returns: Returns the unit heap header pointer. *---------------------------------------------------------------------------*/ static inline MEMiUntHeapHead* GetUnitHeapHeadPtrFromHeapHead_( MEMiHeapHead* pHeapHd ) { return (MEMiUntHeapHead*)AddU32ToPtr( pHeapHd, sizeof(MEMiHeapHead) ); } /*---------------------------------------------------------------------------* Name: IsValidUnitHeapHandle_ Description: Checks the signature to determine whether the heap handle is valid. Arguments: handle: The heap handle Returns: TRUE the heap handle is valid FALSE the heap handle is not valid *---------------------------------------------------------------------------*/ static inline BOOL IsValidUnitHeapHandle_( MEMHeapHandle handle ) { if ( handle == MEM_HEAP_INVALID_HANDLE ) { return FALSE; } { MEMiHeapHead* pHeapHd = handle; return pHeapHd->signature == MEMi_UNTHEAP_SIGNATURE; } } /* ======================================================================== External Functions (Non-Public) ======================================================================== */ /*---------------------------------------------------------------------------* Name: MEMiDumpUnitHeap Description: Displays the information inside unit heap. This function is for debugging. Arguments: heap : Unit heap handle. Returns: None. *---------------------------------------------------------------------------*/ #if defined(_DEBUG) void MEMiDumpUnitHeap( MEMHeapHandle heap ) { ASSERT( IsValidUnitHeapHandle_( heap ) ); { MEMiHeapHead *const pHeapHd = heap; MEMiUntHeapHead *const pUnitHeapHd = GetUnitHeapHeadPtrFromHeapHead_( pHeapHd ); const u32 heapSize = GetOffsetFromPtr( pHeapHd->heapStart, pHeapHd->heapEnd ); const u32 freeSize = MEMCountFreeBlockForUnitHeap( heap ) * pUnitHeapHd->mBlkSize; const u32 usedSize = heapSize - freeSize; MEMiDumpHeapHead(pHeapHd); OSReport(" %d / %d bytes (%6.2f%%) used\n", usedSize, heapSize, 100.0f * usedSize / heapSize); } } // #if defined(_DEBUG) #endif /* ======================================================================== External functions (public) ======================================================================== */ /*---------------------------------------------------------------------------* Name: MEMCreateUnitHeapEx Description: Creates unit heap Arguments: startAddress: Start address of heap area heapSize: Size of heap area memBlockSize: Memory block size alignment: Memory block alignment. 4, 8, 16, or 32 may be specified for the value. optFlag: Option flag. Returns: If the function succeeds, a handle for the created unit heap is returned. If the function fails, MEM_INVALID_HEAP_HANDLE is returned. *---------------------------------------------------------------------------*/ MEMHeapHandle MEMCreateUnitHeapEx( void* startAddress, u32 heapSize, u32 memBlockSize, int alignment, u16 optFlag ) { MEMiHeapHead* pHeapHd; void* heapEnd; ASSERT(startAddress != NULL); // alignment check ASSERT( alignment % MIN_ALIGNMENT == 0 ); ASSERT( MIN_ALIGNMENT <= alignment && alignment <= 32 ); pHeapHd = (MEMiHeapHead*)RoundUpPtr( startAddress, MIN_ALIGNMENT ); heapEnd = RoundDownPtr( AddU32ToPtr( startAddress, heapSize ), MIN_ALIGNMENT ); if ( ComparePtr( pHeapHd, heapEnd ) > 0 ) { return MEM_HEAP_INVALID_HANDLE; } memBlockSize = RoundUp( memBlockSize, alignment ); // Real block size { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( pHeapHd ); void* heapStart = RoundUpPtr( AddU32ToPtr( pUntHeapHd, sizeof(MEMiUntHeapHead) ), alignment ); u32 elementNum; if ( ComparePtr( heapStart, heapEnd ) > 0 ) { return MEM_HEAP_INVALID_HANDLE; } elementNum = GetOffsetFromPtr( heapStart, heapEnd ) / memBlockSize; if ( elementNum == 0 ) { return MEM_HEAP_INVALID_HANDLE; } heapEnd = AddU32ToPtr( heapStart, elementNum * memBlockSize ); MEMiInitHeapHead( // Heap common initialization pHeapHd, MEMi_UNTHEAP_SIGNATURE, heapStart, heapEnd, optFlag ); pUntHeapHd->mbFreeList.head = (MEMiUntHeapMBlockHead*)heapStart; pUntHeapHd->mBlkSize = memBlockSize; { MEMiUntHeapMBlockHead* pMBlkHd = pUntHeapHd->mbFreeList.head; int i; for ( i = 0; i < elementNum - 1; ++i, pMBlkHd = pMBlkHd->pMBlkHdNext ) { pMBlkHd->pMBlkHdNext = (MEMiUntHeapMBlockHead*)AddU32ToPtr( pMBlkHd, memBlockSize ); } pMBlkHd->pMBlkHdNext = NULL; } return pHeapHd; } } /*---------------------------------------------------------------------------* Name: MEMDestroyUnitHeap Description: Destroys unit heap. Arguments: heap : Unit heap handle. Returns: Returns a pointer to the region occupied by the destroyed heap. *---------------------------------------------------------------------------*/ void* MEMDestroyUnitHeap( MEMHeapHandle heap ) { ASSERT( IsValidUnitHeapHandle_(heap) ); MEMiFinalizeHeap(heap); return (void*)heap; } /*---------------------------------------------------------------------------* Name: MEMAllocFromUnitHeap Description: Allocates memory block from unit heap. Arguments: heap : Unit heap handle. Returns: Returns the pointer to the allocated memory block if the allocation is successful. If fails, NULL is returned. *---------------------------------------------------------------------------*/ void* MEMAllocFromUnitHeap( MEMHeapHandle heap ) { MEMiUntHeapMBlockHead* pMBlkHd; ASSERT( IsValidUnitHeapHandle_( heap ) ); { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap ); LockHeap( heap ); pMBlkHd = PopMBlock_( &pUntHeapHd->mbFreeList ); UnlockHeap( heap ); if ( pMBlkHd ) { FillAllocMemory( heap, pMBlkHd, pUntHeapHd->mBlkSize ); } } return pMBlkHd; } /*---------------------------------------------------------------------------* Name: MEMFreeToUnitHeap Description: Returns unit heap to memory block. Arguments: heap : Unit heap handle. memBlock: Pointer to the memory block to be returned. Returns: None. *---------------------------------------------------------------------------*/ void MEMFreeToUnitHeap( MEMHeapHandle heap, void* memBlock ) { ASSERT( IsValidUnitHeapHandle_( heap ) ); if ( memBlock == NULL ) { return; } { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap ); FillFreeMemory( heap, memBlock, pUntHeapHd->mBlkSize ); LockHeap( heap ); PushMBlock_( &pUntHeapHd->mbFreeList, (MEMiUntHeapMBlockHead*)memBlock ); UnlockHeap( heap ); } } /*---------------------------------------------------------------------------* Name: MEMCountFreeBlockForUnitHeap Description: Gets the number of empty memory blocks in the unit heap. Arguments: heap : Unit heap handle. Returns: Returns the number of empty memory blocks in the unit heap. *---------------------------------------------------------------------------*/ u32 MEMCountFreeBlockForUnitHeap( MEMHeapHandle heap ) { u32 cnt = 0; ASSERT(IsValidUnitHeapHandle_(heap)); LockHeap( heap ); { MEMiUntHeapHead* pUntHeapHd = GetUnitHeapHeadPtrFromHeapHead_( heap ); MEMiUntHeapMBlockHead* pMBlkHd = pUntHeapHd->mbFreeList.head; for ( ; pMBlkHd; pMBlkHd = pMBlkHd->pMBlkHdNext ) { ++cnt; } } UnlockHeap( heap ); return cnt; } /*---------------------------------------------------------------------------* Name: MEMCalcHeapSizeForUnitHeap Description: Gets the size of the heap required from the size of the memory blocks and the number of blocks. Arguments: memBlockSize: Size of the memory block (in bytes). memBlockNum: Total number of reserved memory blocks. alignment: Memory block alignment. Returns: Returns the required heap size. *---------------------------------------------------------------------------*/ u32 MEMCalcHeapSizeForUnitHeap( u32 memBlockSize, u32 memBlockNum, int alignment ) { return sizeof(MEMiHeapHead) + sizeof(MEMiUntHeapHead) // The size the heap uses internally + (alignment - 4) // The maximum size required for alignment adjustment + memBlockNum * RoundUp( memBlockSize, alignment ); // The size required for all units }