您的位置:首页 > 其它

FreeRtos heap4源码分析

2016-01-28 17:38 351 查看
=============================== 博客点滴积累,部分话语和知识点来源于网络,感谢网络资源的提供者======

heap4 与heap2 比较相似,也是简单地实现了pvPortMalloc()和vPortFree(),不过对于释放的空闲内存碎片进行了合并,其他的细微区别会在代码说明的,这里只贴与heap2 不一样的地方

/* Assumes 8bit bytes! */

#define heapBITS_PER_BYTE ( ( size_t ) 8 )

/*结合宏heapBITS_PER_BYTE 标记结构体A_BLOCK_LINK的xBlockSize最高位*/

static size_t xBlockAllocatedBit = 0;

/* 定义一个链表结构体,存空闲的内存块指针和大小 */

typedef struct A_BLOCK_LINK

{

struct A_BLOCK_LINK *pxNextFreeBlock;/*<< 下一个空闲块的指针 */

size_t xBlockSize;/*<<空闲块的大小 最高bit为1 表示已经被分配,为0表示空闲 这是与heap2 有区别的地方*/

#if (SUPPORT_HEAP_DEBUG == 1)

TaskHandle_t xHandle;

#endif
} BlockLink_t;

static void prvHeapInit( void )

{

BlockLink_t *pxFirstFreeBlock;

uint8_t *pucAlignedHeap;

uint32_t ulAddress;

size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;

ulAddress = ( uint32_t ) ucHeap;

if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 )

{//调整使其字节对齐,向上取整

ulAddress += ( portBYTE_ALIGNMENT - 1 );
ulAddress &= ~portBYTE_ALIGNMENT_MASK;
xTotalHeapSize -= ulAddress - ( uint32_t ) ucHeap;

}

pucAlignedHeap = ( uint8_t * ) ulAddress;

/* xStart is used to hold a pointer to the first item in the list of free

blocks. The void cast is used to prevent compiler warnings. */

xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;

xStart.xBlockSize = ( size_t ) 0;

/*这一块和heap2有点区别了,heap2 pxEnd 是一个结构体,heap4时,是一个结构体指针

指向ulAddress,这个地址存着pxEnd 结构体*/

ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalHeapSize;

ulAddress -= xHeapStructSize;

ulAddress &= ~portBYTE_ALIGNMENT_MASK;

pxEnd = ( void * ) ulAddress;

pxEnd->xBlockSize = 0;

pxEnd->pxNextFreeBlock = NULL;

/* To start with there is a single free block that is sized to take up the

entire heap space, minus the space taken by pxEnd. */

pxFirstFreeBlock = ( void * ) pucAlignedHeap;

pxFirstFreeBlock->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlock;//结束地址-开始地址= 大小

pxFirstFreeBlock->pxNextFreeBlock = pxEnd;

#if (SUPPORT_HEAP_DEBUG == 1)

pxFirstBlock = pxFirstFreeBlock;

#endif

/* Only one block exists - and it covers the entire usable heap space. */

xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;

xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;

/*设置xBlockAllocatedBit 最高位为1 将来标记内存块是否被分配过*/

xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}

/*-----------------------------------------------------------*/

/*heap4 与heap2 最大的区别就是这个函数了,插入时,会合并内存碎片*/

static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )

{

BlockLink_t *pxIterator;

uint8_t *puc;

/*遍历查找到,内存块地址大于插入块地址,就跳出*/

for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )

{

/* Nothing to do here, just iterate to the right position. */

}

/* Do the block being inserted, and the block it is being inserted after

make a contiguous block of memory? */

puc = ( uint8_t * ) pxIterator;

if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )

{//前一块和插入块相邻,合并内存块
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}

else

{
mtCOVERAGE_TEST_MARKER();
}

puc = ( uint8_t * ) pxBlockToInsert;

if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )

{//后一块和插入块相邻,合并内存块
if( pxIterator->pxNextFreeBlock != pxEnd )
{

/* Form one big block from the two blocks. */

pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;

pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;

}
else
{

pxBlockToInsert->pxNextFreeBlock = pxEnd;

}
}

else

{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}

/* 如果和前一块内存合并了, 内存地址会相等,不用修改指针,若不相等,则需要修改指针插入*/

if( pxIterator != pxBlockToInsert )

{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}

else

{
mtCOVERAGE_TEST_MARKER();
}
}

/*-----------------------------------------------------------*/

void *pvPortMalloc( size_t xWantedSize )

{

BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;

void *pvReturn = NULL;

vTaskSuspendAll();

{

/* 如果是第一次初始化,需要初始化空闲链表. */
if( pxEnd == NULL )
{

prvHeapInit();

}
else
{

mtCOVERAGE_TEST_MARKER();

}
/* 需要分配的内存不能太大 */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{

/* The wanted size is increased so it can contain a BlockLink_t

structure in addition to the requested amount of bytes. */

if( xWantedSize > 0 )

{

xWantedSize += xHeapStructSize;/*分配的地址最前面放这个BlockLink_t结构体*/

if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )

{/* 调整字节对齐 */

xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );

configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

else

{

mtCOVERAGE_TEST_MARKER();

}

if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )

{

/* /*空闲块是从小到大存储,遍历链表,直到找到合适的空闲块 */ */

pxPreviousBlock = &xStart;

pxBlock = xStart.pxNextFreeBlock;

while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )

{

pxPreviousBlock = pxBlock;

pxBlock = pxBlock->pxNextFreeBlock;

}

if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )

{/* 如果该空闲块比较大,剩余的大小大于两个BlockLink_t,则将该块分为两个 */

/* 创建一个新块*/

pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );

configASSERT( ( ( ( uint32_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );

/* 计算新块的大小*/

/* If the end marker was reached then a block of adequate size wasnot found. */

if( pxBlock != pxEnd )

{/* 遍历后找到合适的块 */

/* 返回分配的内存地址 - 分配的地址实际是BlockLink_t + 需要分配的大小,所以返回的地址要跳过BlockLink_t */

pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );

#if (SUPPORT_HEAP_DEBUG == 1)

pxPreviousBlock->pxNextFreeBlock->xHandle = xTaskGetCurrentTaskHandle();

#endif

/* 去掉空闲链表的刚分配的块 */

pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;

pxBlock->xBlockSize = xWantedSize;

/* Insert the new block into the list of free blocks. */

prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );

}

else

{

mtCOVERAGE_TEST_MARKER();

}

xFreeBytesRemaining -= pxBlock->xBlockSize;//减去已经分配的字节数,剩下实际可分配的字节数

if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )

{

xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

/* 标记该内存块已经被分配,并置pxBlock->pxNextFreeBlock = NULL */

pxBlock->xBlockSize |= xBlockAllocatedBit;

pxBlock->pxNextFreeBlock = NULL;

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}

else
{

mtCOVERAGE_TEST_MARKER();

}
traceMALLOC( pvReturn, xWantedSize );
}

( void ) xTaskResumeAll();

#if( configUSE_MALLOC_FAILED_HOOK == 1 )

{
if( pvReturn == NULL )
{

extern void vApplicationMallocFailedHook( void );

vApplicationMallocFailedHook();

}
else
{

mtCOVERAGE_TEST_MARKER();

}
}

#endif

configASSERT( ( ( ( uint32_t ) pvReturn ) & portBYTE_ALIGNMENT_MASK ) == 0 );

return pvReturn;
}

/*-----------------------------------------------------------*/

void vPortFree( void *pv )

{

uint8_t *puc = ( uint8_t * ) pv;

BlockLink_t *pxLink;

if( pv != NULL )

{/* 分配的大小是 实际大小 + heapSTRUCT_SIZE 所以实际的起始地址需要减去heapSTRUCT_SIZE */
puc -= xHeapStructSize;
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
/*被分配的地址,xBlockSize 最高bit为1*/
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{

if( pxLink->pxNextFreeBlock == NULL )/*被分配后pxLink->pxNextFreeBlock 被置位NULL*/

{

/* 修改标志,表示该内存块空闲 */

pxLink->xBlockSize &= ~xBlockAllocatedBit;

vTaskSuspendAll();

{

/* Add this block to the list of free blocks. */

xFreeBytesRemaining += pxLink->xBlockSize;

traceFREE( pv, pxLink->xBlockSize );

prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );

}

( void ) xTaskResumeAll();

}

else

{

mtCOVERAGE_TEST_MARKER();

}

}
else
{

mtCOVERAGE_TEST_MARKER();

}

}
}

/*-----------------------------------------------------------*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: