基于Freertos Heap4的Realloc的编写

      由于发现FreeRTOS(v9.0.0)中并没有对realloc进行支持,所以就自己写了pvPortRealloc函数。

      首先先谈谈Heap4内存管理机制,由xStart为头结点,pxEnd为尾节点构成的一条链表。用来描述ucheap数组中尚未分配的地址块。这些地址块按照地址从小到大插入到链表中。

       当使用pvPortMalloc 申请N个字节数据时,首先会添加一个BlockLink_t结构,其中包含字段xBlockSize和*pxNextFreeBlock。实际上我们申请块的大小为N+sizeof(BlockLink) +( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ))。后面括号中表示8字节对齐。所以我们从xStart头结点开始遍历,直到找到块大小大于xBlockSize的节点。取出该空闲块,其中一部分用作于申请的块,剩下的内存块组成新的空闲块,按照地址大小,插入到链表中。

       当使用vPortFree释放某一块内存时,同样会先获得其BlockLink_t结构体,将该块作为空闲块插入到链表中,其中包括空闲块合并的过程。

       而realloc要做的是将一块已分配的块进行扩充N个字节,如果块尾部还有足够的内存空间,则将其增加到尾部。否则重新分配一块内存,并且把原先内存的内容复制到新开辟的内存中。根据heap4的内存管理策略,即判断在空闲块链表中是否包含源地址块尾部的地址,并且大小大于想要扩充的大小N,如有,则取出该空闲块,其中一部分作为源地址块的扩充内存,剩下的内存块组成新的空闲块,重新插入到链表中。否则,重新pvPortMalloc一块内存并复制源地址的内容,最后vPortFree源地址。

void *pvPortRealloc( uint8_t *srcaddr,size_t xWantedSize )
{
	
	BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
	void *pvReturn = NULL;

	BlockLink_t *pxBlockold,*pxBlockjudge;
	vTaskSuspendAll();
	{
		/* If this is the first call to malloc then the heap will require
		initialisation to setup the list of free blocks. */
		if( pxEnd == NULL )
		{
			prvHeapInit();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	
		/* Check the requested block size is not so large that the top bit is
		set.  The top bit of the block size member of the BlockLink_t structure
		is used to determine who owns the block - the application or the
		kernel, so it must be free. */
		if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
		{
			if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
			{
				/* Byte alignment required. */
				xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
				configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

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

				if(srcaddr == NULL)
				{
					pvReturn = pvPortMalloc(xWantedSize);
					( void ) xTaskResumeAll();
                                         return pvReturn;
				}
				pxBlockold = (BlockLink_t *)(srcaddr - xHeapStructSize);                              //找到源地址对应的BlockLink_t结构体,提取其中的xBlockSize信息
				pxBlockjudge = (BlockLink_t *)((uint8_t*)pxBlockold+((pxBlockold->xBlockSize)&(~xBlockAllocatedBit)));  //找到源地址对应的块的尾部。


				pxPreviousBlock = &xStart;
				pxBlock = xStart.pxNextFreeBlock;
				while(pxBlock != pxBlockjudge&& ( pxBlock->pxNextFreeBlock != NULL ))    //判断源地址块后的下一块是否可用
				{
					pxPreviousBlock = pxBlock;
					pxBlock = pxBlock->pxNextFreeBlock;
				}
				if((xWantedSize< pxBlock->xBlockSize&&(( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE))&&pxBlock == pxBlockjudge) //源地址块的下一块地址可用,并且其块大小大于申请的大小
				{
					pxBlockold->xBlockSize += xWantedSize;
					pxNewBlockLink = (BlockLink_t *)((uint8_t*)pxBlock + xWantedSize);
					pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
					
					pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
						/* Insert the new block into the list of free blocks. */
					prvInsertBlockIntoFreeList( pxNewBlockLink );
					pxBlock->pxNextFreeBlock = NULL;
					pvReturn = srcaddr;
					xFreeBytesRemaining -= xWantedSize;

					if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
					{
						xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
					}
				}
				else
				{
					pvReturn = pvPortMalloc((((pxBlockold->xBlockSize)&(~xBlockAllocatedBit))-xHeapStructSize)+xWantedSize);                //下一块不可用,重新申请一块地址空间,大小为原申请空间加上现在申请空间
					memcpy((uint8_t*)pvReturn,srcaddr,(pxBlockold->xBlockSize&(~xBlockAllocatedBit)-xHeapStructSize));					   
					vPortFree(srcaddr);																									   //释放源地址空间
				}
				
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
		
	}
	( void ) xTaskResumeAll();
	configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
	return pvReturn;
}

 

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值