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_STATIC_ALLOCATION 1
|
||||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
|
#define configSUPPORT_HEAD_REALLOC 0
|
||||||
#define configTOTAL_HEAP_SIZE 4096U
|
#define configTOTAL_HEAP_SIZE 4096U
|
||||||
#define configAPPLICATION_ALLOCATED_HEAP 1
|
#define configAPPLICATION_ALLOCATED_HEAP 1
|
||||||
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
|
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,11 @@
|
||||||
* https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */
|
* https://www.freertos.org/Static_Vs_Dynamic_Memory_Allocation.html. */
|
||||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
#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
|
/* 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
|
* 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
|
* but it must be tailored to each application. Note the heap will appear in
|
||||||
|
|
|
||||||
|
|
@ -2840,6 +2840,14 @@
|
||||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
#endif
|
#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 ) )
|
#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.
|
#error configUSE_STATS_FORMATTING_FUNCTIONS cannot be used without dynamic allocation, but configSUPPORT_DYNAMIC_ALLOCATION is not set to 1.
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,10 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats );
|
||||||
void * pvPortMalloc( size_t xWantedSize ) PRIVILEGED_FUNCTION;
|
void * pvPortMalloc( size_t xWantedSize ) PRIVILEGED_FUNCTION;
|
||||||
void * pvPortCalloc( size_t xNum,
|
void * pvPortCalloc( size_t xNum,
|
||||||
size_t xSize ) PRIVILEGED_FUNCTION;
|
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 vPortFree( void * pv ) PRIVILEGED_FUNCTION;
|
||||||
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
|
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
|
||||||
size_t xPortGetFreeHeapSize( 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 )
|
size_t xPortGetFreeHeapSize( void )
|
||||||
{
|
{
|
||||||
return xFreeBytesRemaining;
|
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 )
|
size_t xPortGetFreeHeapSize( void )
|
||||||
{
|
{
|
||||||
return xFreeBytesRemaining;
|
return xFreeBytesRemaining;
|
||||||
|
|
@ -560,6 +798,9 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* PRIVI
|
||||||
portPOINTER_SIZE_TYPE xAddress;
|
portPOINTER_SIZE_TYPE xAddress;
|
||||||
const HeapRegion_t * pxHeapRegion;
|
const HeapRegion_t * pxHeapRegion;
|
||||||
|
|
||||||
|
/* Check for NULL pointer */
|
||||||
|
configASSERT(pxHeapRegions != NULL);
|
||||||
|
|
||||||
/* Can only call once! */
|
/* Can only call once! */
|
||||||
configASSERT( pxEnd == NULL );
|
configASSERT( pxEnd == NULL );
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue