mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-01-21 09:10:37 -05:00
[Feature] Support pvPortRealloc
This commit is contained in:
parent
3ace38969b
commit
10f3405880
6 changed files with 497 additions and 0 deletions
|
|
@ -72,6 +72,7 @@
|
|||
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configSUPPORT_HEAD_REALLOC 0
|
||||
#define configTOTAL_HEAP_SIZE 4096U
|
||||
#define configAPPLICATION_ALLOCATED_HEAP 1
|
||||
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
|
||||
|
|
|
|||
|
|
@ -283,6 +283,11 @@
|
|||
* https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
|
||||
/* Set configSUPPORT_HEAD_REALLOC to 1 to include FreeRTOS API functions
|
||||
* that support reallocating memory blocks in the build. Set to 0 to exclude
|
||||
* realloc support from the build. Defaults to 0 if left undefined. */
|
||||
#define configSUPPORT_HEAD_REALLOC 0
|
||||
|
||||
/* Sets the total size of the FreeRTOS heap, in bytes, when heap_1.c, heap_2.c
|
||||
* or heap_4.c are included in the build. This value is defaulted to 4096 bytes
|
||||
* but it must be tailored to each application. Note the heap will appear in
|
||||
|
|
|
|||
|
|
@ -2840,6 +2840,14 @@
|
|||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#endif
|
||||
|
||||
#ifndef configSUPPORT_HEAD_REALLOC
|
||||
#define configSUPPORT_HEAD_REALLOC 0
|
||||
#endif
|
||||
|
||||
#if ( ( configSUPPORT_HEAD_REALLOC > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION != 1 ) )
|
||||
#error configSUPPORT_HEAD_REALLOC cannot be used without dynamic allocation, but configSUPPORT_HEAD_REALLOC is not set to 1.
|
||||
#endif
|
||||
|
||||
#if ( ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION != 1 ) )
|
||||
#error configUSE_STATS_FORMATTING_FUNCTIONS cannot be used without dynamic allocation, but configSUPPORT_DYNAMIC_ALLOCATION is not set to 1.
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -189,6 +189,10 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats );
|
|||
void * pvPortMalloc( size_t xWantedSize ) PRIVILEGED_FUNCTION;
|
||||
void * pvPortCalloc( size_t xNum,
|
||||
size_t xSize ) PRIVILEGED_FUNCTION;
|
||||
#if ( configSUPPORT_HEAD_REALLOC == 1 )
|
||||
void *pvPortRealloc( void *pv,
|
||||
size_t xWantedSize ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
void vPortFree( void * pv ) PRIVILEGED_FUNCTION;
|
||||
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
|
||||
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||
|
|
|
|||
|
|
@ -410,6 +410,244 @@ void vPortFree( void * pv )
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configSUPPORT_HEAD_REALLOC == 1 )
|
||||
/*
|
||||
* pvPortRealloc - Reallocate memory block size
|
||||
*
|
||||
* Description: Resize an allocated memory block, attempting to expand or shrink
|
||||
* the block in place. If in-place resize is not possible, allocate a new block
|
||||
* and copy the data.
|
||||
*
|
||||
* Parameters:
|
||||
* pv - Pointer to the previously allocated memory block
|
||||
* xWantedSize - New requested size of user data (in bytes)
|
||||
*
|
||||
* Return Value:
|
||||
* On success: Pointer to the new memory block (may be the same as original)
|
||||
* On failure: NULL
|
||||
*
|
||||
* Behavior:
|
||||
* - When pv is NULL, equivalent to pvPortMalloc(xWantedSize)
|
||||
* - When xWantedSize is 0, equivalent to vPortFree(pv)
|
||||
* - Resize strategy:
|
||||
* 1. If new size <= original size, attempt to shrink the block
|
||||
* 2. If new size > original size, attempt to expand by merging with adjacent free block
|
||||
* 3. If in-place resize fails, allocate new block and copy data
|
||||
*/
|
||||
void *pvPortRealloc( void *pv,
|
||||
size_t xWantedSize )
|
||||
{
|
||||
BlockLink_t *pxBlock;
|
||||
BlockLink_t *pxPreviousBlock;
|
||||
BlockLink_t *pxNewBlockLink;
|
||||
BlockLink_t *pxAdjacentFreeBlock;
|
||||
void *pvReturn = NULL;
|
||||
size_t xOriginalSize;
|
||||
size_t xNewBlockSize;
|
||||
size_t xAdditionalRequiredSize;
|
||||
size_t xCopySize;
|
||||
|
||||
/* Handle NULL pointer case - equivalent to malloc */
|
||||
if( pv == NULL )
|
||||
{
|
||||
return pvPortMalloc( xWantedSize );
|
||||
}
|
||||
|
||||
/* Handle zero size case - equivalent to free */
|
||||
if( xWantedSize == 0 )
|
||||
{
|
||||
vPortFree( pv );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate new block size with overhead (header size and alignment) */
|
||||
xNewBlockSize = xWantedSize;
|
||||
if( heapADD_WILL_OVERFLOW( xNewBlockSize, xHeapStructSize ) == 0 )
|
||||
{
|
||||
xNewBlockSize += xHeapStructSize;
|
||||
if( ( xNewBlockSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
||||
{
|
||||
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xNewBlockSize & portBYTE_ALIGNMENT_MASK );
|
||||
if( heapADD_WILL_OVERFLOW( xNewBlockSize, xAdditionalRequiredSize ) == 0 )
|
||||
{
|
||||
xNewBlockSize += xAdditionalRequiredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the block header from the user pointer and validate it */
|
||||
pxBlock = ( BlockLink_t * )( ( uint8_t * )pv - xHeapStructSize );
|
||||
heapVALIDATE_BLOCK_POINTER( pxBlock );
|
||||
if( ( heapBLOCK_IS_ALLOCATED( pxBlock ) == 0 ) || ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the original block size (without the allocated bit)
|
||||
* Check if there's enough free memory to expand the block */
|
||||
xOriginalSize = pxBlock->xBlockSize & ~heapBLOCK_ALLOCATED_BITMASK;
|
||||
if( ( xOriginalSize < xNewBlockSize ) && ( xFreeBytesRemaining < ( xNewBlockSize - xOriginalSize ) ) )
|
||||
{
|
||||
/* Not enough memory to expand the block */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the amount of user data to copy (excluding the block header).
|
||||
* The user data size is the block size minus the header size.
|
||||
* Limit the copy size to the requested size to avoid copying too much data. */
|
||||
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( xOriginalSize, xHeapStructSize ) == 0 );
|
||||
xCopySize = xOriginalSize - xHeapStructSize;
|
||||
if( xWantedSize < xCopySize )
|
||||
{
|
||||
xCopySize = xWantedSize;
|
||||
}
|
||||
|
||||
/* Enter critical section - protect heap structure from concurrent access */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Case 1: Shrink the block (new size is smaller than or equal to original)
|
||||
* Check if the remaining space is large enough to create a separate free block */
|
||||
if( xNewBlockSize <= xOriginalSize )
|
||||
{
|
||||
/* Create a new free block from the remaining space */
|
||||
if( ( xOriginalSize - xNewBlockSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
pxNewBlockLink = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xNewBlockSize );
|
||||
configASSERT( ( ( ( size_t )pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
pxNewBlockLink->xBlockSize = xOriginalSize - xNewBlockSize;
|
||||
xFreeBytesRemaining += pxNewBlockLink->xBlockSize;
|
||||
prvInsertBlockIntoFreeList( pxNewBlockLink );
|
||||
heapFREE_BLOCK( pxBlock );
|
||||
pxBlock->xBlockSize = xNewBlockSize;
|
||||
heapALLOCATE_BLOCK( pxBlock );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
pvReturn = pv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Case 2: Try to expand by merging with next free block */
|
||||
pxAdjacentFreeBlock = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xOriginalSize );
|
||||
configASSERT( ( ( ( size_t )pxAdjacentFreeBlock ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
|
||||
/* Traverse the free list to find if the adjacent block is actually free.
|
||||
* The free list is ordered by address, so we can search efficiently.*/
|
||||
pxPreviousBlock = &xStart;
|
||||
while( ( pxPreviousBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( pxAdjacentFreeBlock ) ) &&
|
||||
( pxPreviousBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
|
||||
{
|
||||
pxPreviousBlock = heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock );
|
||||
heapVALIDATE_BLOCK_POINTER( pxPreviousBlock );
|
||||
}
|
||||
|
||||
if( pxPreviousBlock->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( pxAdjacentFreeBlock ) )
|
||||
{
|
||||
configASSERT( heapBLOCK_SIZE_IS_VALID( pxAdjacentFreeBlock->xBlockSize ) );
|
||||
if( !heapADD_WILL_OVERFLOW( xOriginalSize, pxAdjacentFreeBlock->xBlockSize ) )
|
||||
{
|
||||
/* Found a suitable adjacent free block that can provide enough space. */
|
||||
if( ( xOriginalSize + pxAdjacentFreeBlock->xBlockSize ) >= xNewBlockSize )
|
||||
{
|
||||
/* Remove the adjacent free block from the free list and merge it with the allocated block. */
|
||||
pxPreviousBlock->pxNextFreeBlock = pxAdjacentFreeBlock->pxNextFreeBlock;
|
||||
xFreeBytesRemaining -= pxAdjacentFreeBlock->xBlockSize;
|
||||
heapFREE_BLOCK( pxBlock );
|
||||
pxBlock->xBlockSize = xOriginalSize + pxAdjacentFreeBlock->xBlockSize;
|
||||
|
||||
/* If the merged block is larger than needed, split the excess space
|
||||
* into a new free block. */
|
||||
if( ( pxBlock->xBlockSize - xNewBlockSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
pxNewBlockLink = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xNewBlockSize );
|
||||
configASSERT( ( ( ( size_t )pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xNewBlockSize;
|
||||
xFreeBytesRemaining += pxNewBlockLink->xBlockSize;
|
||||
prvInsertBlockIntoFreeList( pxNewBlockLink );
|
||||
pxBlock->xBlockSize = xNewBlockSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
heapALLOCATE_BLOCK( pxBlock );
|
||||
pvReturn = pv;
|
||||
|
||||
/* Update minimum free size statistic if memory was consumed */
|
||||
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
|
||||
{
|
||||
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Exit critical section - heap structure modification complete */
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
/* Case 3: If in-place resize failed, allocate a new block and move the data.
|
||||
* This is more expensive as it involves:
|
||||
* 1. Allocating a new block with the requested size
|
||||
* 2. Copying the user data from the old block to the new block
|
||||
* 3. Freeing the old block
|
||||
* Note: Statistics are updated by the called functions (malloc and free). */
|
||||
if( pvReturn == NULL )
|
||||
{
|
||||
pvReturn = pvPortMalloc( xWantedSize );
|
||||
if( pvReturn != NULL )
|
||||
{
|
||||
/* Copy user data from old block to new block (up to the smaller of old or new size) */
|
||||
( void )memcpy( pvReturn, pv, xCopySize );
|
||||
vPortFree( pv );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
configASSERT( ( ( ( size_t )pvReturn ) & ( size_t )portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
return pvReturn;
|
||||
}
|
||||
#endif /* if ( configSUPPORT_HEAD_REALLOC == 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetFreeHeapSize( void )
|
||||
{
|
||||
return xFreeBytesRemaining;
|
||||
|
|
|
|||
|
|
@ -445,6 +445,244 @@ void vPortFree( void * pv )
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configSUPPORT_HEAD_REALLOC == 1 )
|
||||
/*
|
||||
* pvPortRealloc - Reallocate memory block size
|
||||
*
|
||||
* Description: Resize an allocated memory block, attempting to expand or shrink
|
||||
* the block in place. If in-place resize is not possible, allocate a new block
|
||||
* and copy the data.
|
||||
*
|
||||
* Parameters:
|
||||
* pv - Pointer to the previously allocated memory block
|
||||
* xWantedSize - New requested size of user data (in bytes)
|
||||
*
|
||||
* Return Value:
|
||||
* On success: Pointer to the new memory block (may be the same as original)
|
||||
* On failure: NULL
|
||||
*
|
||||
* Behavior:
|
||||
* - When pv is NULL, equivalent to pvPortMalloc(xWantedSize)
|
||||
* - When xWantedSize is 0, equivalent to vPortFree(pv)
|
||||
* - Resize strategy:
|
||||
* 1. If new size <= original size, attempt to shrink the block
|
||||
* 2. If new size > original size, attempt to expand by merging with adjacent free block
|
||||
* 3. If in-place resize fails, allocate new block and copy data
|
||||
*/
|
||||
void *pvPortRealloc( void *pv,
|
||||
size_t xWantedSize )
|
||||
{
|
||||
BlockLink_t *pxBlock;
|
||||
BlockLink_t *pxPreviousBlock;
|
||||
BlockLink_t *pxNewBlockLink;
|
||||
BlockLink_t *pxAdjacentFreeBlock;
|
||||
void *pvReturn = NULL;
|
||||
size_t xOriginalSize;
|
||||
size_t xNewBlockSize;
|
||||
size_t xAdditionalRequiredSize;
|
||||
size_t xCopySize;
|
||||
|
||||
/* Handle NULL pointer case - equivalent to malloc */
|
||||
if( pv == NULL )
|
||||
{
|
||||
return pvPortMalloc( xWantedSize );
|
||||
}
|
||||
|
||||
/* Handle zero size case - equivalent to free */
|
||||
if( xWantedSize == 0 )
|
||||
{
|
||||
vPortFree( pv );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate new block size with overhead (header size and alignment) */
|
||||
xNewBlockSize = xWantedSize;
|
||||
if( heapADD_WILL_OVERFLOW( xNewBlockSize, xHeapStructSize ) == 0 )
|
||||
{
|
||||
xNewBlockSize += xHeapStructSize;
|
||||
if( ( xNewBlockSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
||||
{
|
||||
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xNewBlockSize & portBYTE_ALIGNMENT_MASK );
|
||||
if( heapADD_WILL_OVERFLOW( xNewBlockSize, xAdditionalRequiredSize ) == 0 )
|
||||
{
|
||||
xNewBlockSize += xAdditionalRequiredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the block header from the user pointer and validate it */
|
||||
pxBlock = ( BlockLink_t * )( ( uint8_t * )pv - xHeapStructSize );
|
||||
heapVALIDATE_BLOCK_POINTER( pxBlock );
|
||||
if( ( heapBLOCK_IS_ALLOCATED( pxBlock ) == 0 ) || ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the original block size (without the allocated bit)
|
||||
* Check if there's enough free memory to expand the block */
|
||||
xOriginalSize = pxBlock->xBlockSize & ~heapBLOCK_ALLOCATED_BITMASK;
|
||||
if( ( xOriginalSize < xNewBlockSize ) && ( xFreeBytesRemaining < ( xNewBlockSize - xOriginalSize ) ) )
|
||||
{
|
||||
/* Not enough memory to expand the block */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the amount of user data to copy (excluding the block header).
|
||||
* The user data size is the block size minus the header size.
|
||||
* Limit the copy size to the requested size to avoid copying too much data. */
|
||||
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( xOriginalSize, xHeapStructSize ) == 0 );
|
||||
xCopySize = xOriginalSize - xHeapStructSize;
|
||||
if( xWantedSize < xCopySize )
|
||||
{
|
||||
xCopySize = xWantedSize;
|
||||
}
|
||||
|
||||
/* Enter critical section - protect heap structure from concurrent access */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Case 1: Shrink the block (new size is smaller than or equal to original)
|
||||
* Check if the remaining space is large enough to create a separate free block */
|
||||
if( xNewBlockSize <= xOriginalSize )
|
||||
{
|
||||
/* Create a new free block from the remaining space */
|
||||
if( ( xOriginalSize - xNewBlockSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
pxNewBlockLink = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xNewBlockSize );
|
||||
configASSERT( ( ( ( size_t )pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
pxNewBlockLink->xBlockSize = xOriginalSize - xNewBlockSize;
|
||||
xFreeBytesRemaining += pxNewBlockLink->xBlockSize;
|
||||
prvInsertBlockIntoFreeList( pxNewBlockLink );
|
||||
heapFREE_BLOCK( pxBlock );
|
||||
pxBlock->xBlockSize = xNewBlockSize;
|
||||
heapALLOCATE_BLOCK( pxBlock );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
pvReturn = pv;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Case 2: Try to expand by merging with next free block */
|
||||
pxAdjacentFreeBlock = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xOriginalSize );
|
||||
configASSERT( ( ( ( size_t )pxAdjacentFreeBlock ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
|
||||
/* Traverse the free list to find if the adjacent block is actually free.
|
||||
* The free list is ordered by address, so we can search efficiently.*/
|
||||
pxPreviousBlock = &xStart;
|
||||
while( ( pxPreviousBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( pxAdjacentFreeBlock ) ) &&
|
||||
( pxPreviousBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
|
||||
{
|
||||
pxPreviousBlock = heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock );
|
||||
heapVALIDATE_BLOCK_POINTER( pxPreviousBlock );
|
||||
}
|
||||
|
||||
if( pxPreviousBlock->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( pxAdjacentFreeBlock ) )
|
||||
{
|
||||
configASSERT( heapBLOCK_SIZE_IS_VALID( pxAdjacentFreeBlock->xBlockSize ) );
|
||||
if( !heapADD_WILL_OVERFLOW( xOriginalSize, pxAdjacentFreeBlock->xBlockSize ) )
|
||||
{
|
||||
/* Found a suitable adjacent free block that can provide enough space. */
|
||||
if( ( xOriginalSize + pxAdjacentFreeBlock->xBlockSize ) >= xNewBlockSize )
|
||||
{
|
||||
/* Remove the adjacent free block from the free list and merge it with the allocated block. */
|
||||
pxPreviousBlock->pxNextFreeBlock = pxAdjacentFreeBlock->pxNextFreeBlock;
|
||||
xFreeBytesRemaining -= pxAdjacentFreeBlock->xBlockSize;
|
||||
heapFREE_BLOCK( pxBlock );
|
||||
pxBlock->xBlockSize = xOriginalSize + pxAdjacentFreeBlock->xBlockSize;
|
||||
|
||||
/* If the merged block is larger than needed, split the excess space
|
||||
* into a new free block. */
|
||||
if( ( pxBlock->xBlockSize - xNewBlockSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
pxNewBlockLink = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xNewBlockSize );
|
||||
configASSERT( ( ( ( size_t )pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xNewBlockSize;
|
||||
xFreeBytesRemaining += pxNewBlockLink->xBlockSize;
|
||||
prvInsertBlockIntoFreeList( pxNewBlockLink );
|
||||
pxBlock->xBlockSize = xNewBlockSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
heapALLOCATE_BLOCK( pxBlock );
|
||||
pvReturn = pv;
|
||||
|
||||
/* Update minimum free size statistic if memory was consumed */
|
||||
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
|
||||
{
|
||||
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Exit critical section - heap structure modification complete */
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
/* Case 3: If in-place resize failed, allocate a new block and move the data.
|
||||
* This is more expensive as it involves:
|
||||
* 1. Allocating a new block with the requested size
|
||||
* 2. Copying the user data from the old block to the new block
|
||||
* 3. Freeing the old block
|
||||
* Note: Statistics are updated by the called functions (malloc and free). */
|
||||
if( pvReturn == NULL )
|
||||
{
|
||||
pvReturn = pvPortMalloc( xWantedSize );
|
||||
if( pvReturn != NULL )
|
||||
{
|
||||
/* Copy user data from old block to new block (up to the smaller of old or new size) */
|
||||
( void )memcpy( pvReturn, pv, xCopySize );
|
||||
vPortFree( pv );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
configASSERT( ( ( ( size_t )pvReturn ) & ( size_t )portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
return pvReturn;
|
||||
}
|
||||
#endif /* if ( configSUPPORT_HEAD_REALLOC == 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetFreeHeapSize( void )
|
||||
{
|
||||
return xFreeBytesRemaining;
|
||||
|
|
@ -560,6 +798,9 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* PRIVI
|
|||
portPOINTER_SIZE_TYPE xAddress;
|
||||
const HeapRegion_t * pxHeapRegion;
|
||||
|
||||
/* Check for NULL pointer */
|
||||
configASSERT(pxHeapRegions != NULL);
|
||||
|
||||
/* Can only call once! */
|
||||
configASSERT( pxEnd == NULL );
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue