@@ -410,6 +410,244 @@ void vPortFree( void * pv )
410410}
411411/*-----------------------------------------------------------*/
412412
413+ #if ( configSUPPORT_HEAP_REALLOC == 1 )
414+ /*
415+ * pvPortRealloc - Reallocate memory block size
416+ *
417+ * Description: Resize an allocated memory block, attempting to expand or shrink
418+ * the block in place. If in-place resize is not possible, allocate a new block
419+ * and copy the data.
420+ *
421+ * Parameters:
422+ * pv - Pointer to the previously allocated memory block
423+ * xWantedSize - New requested size of user data (in bytes)
424+ *
425+ * Return Value:
426+ * On success: Pointer to the new memory block (may be the same as original)
427+ * On failure: NULL
428+ *
429+ * Behavior:
430+ * - When pv is NULL, equivalent to pvPortMalloc(xWantedSize)
431+ * - When xWantedSize is 0, equivalent to vPortFree(pv)
432+ * - Resize strategy:
433+ * 1. If new size <= original size, attempt to shrink the block
434+ * 2. If new size > original size, attempt to expand by merging with adjacent free block
435+ * 3. If in-place resize fails, allocate new block and copy data
436+ */
437+ void * pvPortRealloc ( void * pv ,
438+ size_t xWantedSize )
439+ {
440+ BlockLink_t * pxBlock ;
441+ BlockLink_t * pxPreviousBlock ;
442+ BlockLink_t * pxNewBlockLink ;
443+ BlockLink_t * pxAdjacentFreeBlock ;
444+ void * pvReturn = NULL ;
445+ size_t xOriginalSize ;
446+ size_t xNewBlockSize ;
447+ size_t xAdditionalRequiredSize ;
448+ size_t xCopySize ;
449+
450+ /* Handle NULL pointer case - equivalent to malloc */
451+ if ( pv == NULL )
452+ {
453+ return pvPortMalloc ( xWantedSize );
454+ }
455+
456+ /* Handle zero size case - equivalent to free */
457+ if ( xWantedSize == 0 )
458+ {
459+ vPortFree ( pv );
460+ return NULL ;
461+ }
462+
463+ /* Calculate new block size with overhead (header size and alignment) */
464+ xNewBlockSize = xWantedSize ;
465+ if ( heapADD_WILL_OVERFLOW ( xNewBlockSize , xHeapStructSize ) == 0 )
466+ {
467+ xNewBlockSize += xHeapStructSize ;
468+ if ( ( xNewBlockSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
469+ {
470+ xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xNewBlockSize & portBYTE_ALIGNMENT_MASK );
471+ if ( heapADD_WILL_OVERFLOW ( xNewBlockSize , xAdditionalRequiredSize ) == 0 )
472+ {
473+ xNewBlockSize += xAdditionalRequiredSize ;
474+ }
475+ else
476+ {
477+ return NULL ;
478+ }
479+ }
480+ else
481+ {
482+ mtCOVERAGE_TEST_MARKER ();
483+ }
484+ }
485+ else
486+ {
487+ return NULL ;
488+ }
489+
490+ /* Get the block header from the user pointer and validate it */
491+ pxBlock = ( BlockLink_t * )( ( uint8_t * )pv - xHeapStructSize );
492+ heapVALIDATE_BLOCK_POINTER ( pxBlock );
493+ if ( ( heapBLOCK_IS_ALLOCATED ( pxBlock ) == 0 ) || ( pxBlock -> pxNextFreeBlock != heapPROTECT_BLOCK_POINTER ( NULL ) ) )
494+ {
495+ return NULL ;
496+ }
497+
498+ /* Calculate the original block size (without the allocated bit)
499+ * Check if there's enough free memory to expand the block */
500+ xOriginalSize = pxBlock -> xBlockSize & ~heapBLOCK_ALLOCATED_BITMASK ;
501+ if ( ( xOriginalSize < xNewBlockSize ) && ( xFreeBytesRemaining < ( xNewBlockSize - xOriginalSize ) ) )
502+ {
503+ /* Not enough memory to expand the block */
504+ return NULL ;
505+ }
506+
507+ /* Calculate the amount of user data to copy (excluding the block header).
508+ * The user data size is the block size minus the header size.
509+ * Limit the copy size to the requested size to avoid copying too much data. */
510+ configASSERT ( heapSUBTRACT_WILL_UNDERFLOW ( xOriginalSize , xHeapStructSize ) == 0 );
511+ xCopySize = xOriginalSize - xHeapStructSize ;
512+ if ( xWantedSize < xCopySize )
513+ {
514+ xCopySize = xWantedSize ;
515+ }
516+
517+ /* Enter critical section - protect heap structure from concurrent access */
518+ vTaskSuspendAll ();
519+ {
520+ /* Case 1: Shrink the block (new size is smaller than or equal to original)
521+ * Check if the remaining space is large enough to create a separate free block */
522+ if ( xNewBlockSize <= xOriginalSize )
523+ {
524+ /* Create a new free block from the remaining space */
525+ if ( ( xOriginalSize - xNewBlockSize ) > heapMINIMUM_BLOCK_SIZE )
526+ {
527+ pxNewBlockLink = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xNewBlockSize );
528+ configASSERT ( ( ( ( size_t )pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
529+ pxNewBlockLink -> xBlockSize = xOriginalSize - xNewBlockSize ;
530+ xFreeBytesRemaining += pxNewBlockLink -> xBlockSize ;
531+ prvInsertBlockIntoFreeList ( pxNewBlockLink );
532+ heapFREE_BLOCK ( pxBlock );
533+ pxBlock -> xBlockSize = xNewBlockSize ;
534+ heapALLOCATE_BLOCK ( pxBlock );
535+ }
536+ else
537+ {
538+ mtCOVERAGE_TEST_MARKER ();
539+ }
540+ pvReturn = pv ;
541+ }
542+ else
543+ {
544+ /* Case 2: Try to expand by merging with next free block */
545+ pxAdjacentFreeBlock = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xOriginalSize );
546+ configASSERT ( ( ( ( size_t )pxAdjacentFreeBlock ) & portBYTE_ALIGNMENT_MASK ) == 0 );
547+
548+ /* Traverse the free list to find if the adjacent block is actually free.
549+ * The free list is ordered by address, so we can search efficiently.*/
550+ pxPreviousBlock = & xStart ;
551+ while ( ( pxPreviousBlock -> pxNextFreeBlock != heapPROTECT_BLOCK_POINTER ( pxAdjacentFreeBlock ) ) &&
552+ ( pxPreviousBlock -> pxNextFreeBlock != heapPROTECT_BLOCK_POINTER ( NULL ) ) )
553+ {
554+ pxPreviousBlock = heapPROTECT_BLOCK_POINTER ( pxPreviousBlock -> pxNextFreeBlock );
555+ heapVALIDATE_BLOCK_POINTER ( pxPreviousBlock );
556+ }
557+
558+ if ( pxPreviousBlock -> pxNextFreeBlock == heapPROTECT_BLOCK_POINTER ( pxAdjacentFreeBlock ) )
559+ {
560+ configASSERT ( heapBLOCK_SIZE_IS_VALID ( pxAdjacentFreeBlock -> xBlockSize ) );
561+ if ( !heapADD_WILL_OVERFLOW ( xOriginalSize , pxAdjacentFreeBlock -> xBlockSize ) )
562+ {
563+ /* Found a suitable adjacent free block that can provide enough space. */
564+ if ( ( xOriginalSize + pxAdjacentFreeBlock -> xBlockSize ) >= xNewBlockSize )
565+ {
566+ /* Remove the adjacent free block from the free list and merge it with the allocated block. */
567+ pxPreviousBlock -> pxNextFreeBlock = pxAdjacentFreeBlock -> pxNextFreeBlock ;
568+ xFreeBytesRemaining -= pxAdjacentFreeBlock -> xBlockSize ;
569+ heapFREE_BLOCK ( pxBlock );
570+ pxBlock -> xBlockSize = xOriginalSize + pxAdjacentFreeBlock -> xBlockSize ;
571+
572+ /* If the merged block is larger than needed, split the excess space
573+ * into a new free block. */
574+ if ( ( pxBlock -> xBlockSize - xNewBlockSize ) > heapMINIMUM_BLOCK_SIZE )
575+ {
576+ pxNewBlockLink = ( BlockLink_t * )( ( ( uint8_t * )pxBlock ) + xNewBlockSize );
577+ configASSERT ( ( ( ( size_t )pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
578+ pxNewBlockLink -> xBlockSize = pxBlock -> xBlockSize - xNewBlockSize ;
579+ xFreeBytesRemaining += pxNewBlockLink -> xBlockSize ;
580+ prvInsertBlockIntoFreeList ( pxNewBlockLink );
581+ pxBlock -> xBlockSize = xNewBlockSize ;
582+ }
583+ else
584+ {
585+ mtCOVERAGE_TEST_MARKER ();
586+ }
587+
588+ heapALLOCATE_BLOCK ( pxBlock );
589+ pvReturn = pv ;
590+
591+ /* Update minimum free size statistic if memory was consumed */
592+ if ( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
593+ {
594+ xMinimumEverFreeBytesRemaining = xFreeBytesRemaining ;
595+ }
596+ else
597+ {
598+ mtCOVERAGE_TEST_MARKER ();
599+ }
600+ }
601+ else
602+ {
603+ mtCOVERAGE_TEST_MARKER ();
604+ }
605+ }
606+ else
607+ {
608+ mtCOVERAGE_TEST_MARKER ();
609+ }
610+ }
611+ else
612+ {
613+ mtCOVERAGE_TEST_MARKER ();
614+ }
615+ }
616+ }
617+ /* Exit critical section - heap structure modification complete */
618+ ( void ) xTaskResumeAll ();
619+
620+ /* Case 3: If in-place resize failed, allocate a new block and move the data.
621+ * This is more expensive as it involves:
622+ * 1. Allocating a new block with the requested size
623+ * 2. Copying the user data from the old block to the new block
624+ * 3. Freeing the old block
625+ * Note: Statistics are updated by the called functions (malloc and free). */
626+ if ( pvReturn == NULL )
627+ {
628+ pvReturn = pvPortMalloc ( xWantedSize );
629+ if ( pvReturn != NULL )
630+ {
631+ /* Copy user data from old block to new block (up to the smaller of old or new size) */
632+ ( void )memcpy ( pvReturn , pv , xCopySize );
633+ vPortFree ( pv );
634+ }
635+ else
636+ {
637+ mtCOVERAGE_TEST_MARKER ();
638+ }
639+ }
640+ else
641+ {
642+ mtCOVERAGE_TEST_MARKER ();
643+ }
644+
645+ configASSERT ( ( ( ( size_t )pvReturn ) & ( size_t )portBYTE_ALIGNMENT_MASK ) == 0 );
646+ return pvReturn ;
647+ }
648+ #endif /* if ( configSUPPORT_HEAP_REALLOC == 1 ) */
649+ /*-----------------------------------------------------------*/
650+
413651size_t xPortGetFreeHeapSize ( void )
414652{
415653 return xFreeBytesRemaining ;
0 commit comments