diff --git a/include/portable.h b/include/portable.h index 22bb9b0ea..0feedad68 100644 --- a/include/portable.h +++ b/include/portable.h @@ -173,6 +173,8 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats ); * Map to the memory management routines required for the port. */ void * pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION; +void * pvPortCalloc( size_t xNum, + size_t xSize ) PRIVILEGED_FUNCTION; void vPortFree( void * pv ) PRIVILEGED_FUNCTION; void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION; size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION; diff --git a/portable/MemMang/heap_2.c b/portable/MemMang/heap_2.c index 4974f1432..85ebdf2e4 100644 --- a/portable/MemMang/heap_2.c +++ b/portable/MemMang/heap_2.c @@ -36,6 +36,7 @@ * memory management pages of https://www.FreeRTOS.org for more information. */ #include +#include /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining * all the API functions to use the MPU wrappers. That should only be done when @@ -51,13 +52,30 @@ #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 #endif +#ifndef configHEAP_CLEAR_MEMORY_ON_FREE + #define configHEAP_CLEAR_MEMORY_ON_FREE 0 +#endif + /* A few bytes might be lost to byte aligning the heap start address. */ #define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) -/* - * Initialises the heap structures before their first use. - */ -static void prvHeapInit( void ); +/* Assumes 8bit bytes! */ +#define heapBITS_PER_BYTE ( ( size_t ) 8 ) + +/* Check if multiplying a and b will result in overflow. */ +#define heapMULTIPLY_WILL_OVERFLOW( a, b, max ) ( ( ( a ) > 0 ) && ( ( b ) > ( ( max ) / ( a ) ) ) ) + +/* MSB of the xBlockSize member of an BlockLink_t structure is used to track + * the allocation status of a block. When MSB of the xBlockSize member of + * an BlockLink_t structure is set then the block belongs to the application. + * When the bit is free the block is still part of the free heap space. */ +#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) ) +#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 ) +#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 ) +#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK ) +#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK ) + +/*-----------------------------------------------------------*/ /* Allocate the memory for the heap. */ #if ( configAPPLICATION_ALLOCATED_HEAP == 1 ) @@ -66,7 +84,7 @@ static void prvHeapInit( void ); * heap - probably so it can be placed in a special segment or address. */ extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; #else - static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; + PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; #endif /* configAPPLICATION_ALLOCATED_HEAP */ @@ -83,11 +101,20 @@ static const uint16_t heapSTRUCT_SIZE = ( ( sizeof( BlockLink_t ) + ( portBYTE_A #define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) /* Create a couple of list links to mark the start and end of the list. */ -static BlockLink_t xStart, xEnd; +PRIVILEGED_DATA static BlockLink_t xStart, xEnd; /* Keeps track of the number of free bytes remaining, but says nothing about * fragmentation. */ -static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE; +PRIVILEGED_DATA static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE; + +/*-----------------------------------------------------------*/ + +/* + * Initialises the heap structures before their first use. + */ +static void prvHeapInit( void ) PRIVILEGED_FUNCTION; + +/*-----------------------------------------------------------*/ /* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ @@ -120,7 +147,7 @@ static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE; void * pvPortMalloc( size_t xWantedSize ) { BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink; - static BaseType_t xHeapHasBeenInitialised = pdFALSE; + PRIVILEGED_DATA static BaseType_t xHeapHasBeenInitialised = pdFALSE; void * pvReturn = NULL; vTaskSuspendAll(); @@ -133,72 +160,84 @@ void * pvPortMalloc( size_t xWantedSize ) xHeapHasBeenInitialised = pdTRUE; } - /* The wanted size must be increased so it can contain a BlockLink_t - * structure in addition to the requested amount of bytes. */ - if( ( xWantedSize > 0 ) && - ( ( xWantedSize + heapSTRUCT_SIZE ) > xWantedSize ) ) /* Overflow check */ + /* 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( heapBLOCK_SIZE_IS_VALID( xWantedSize ) ) { - xWantedSize += heapSTRUCT_SIZE; - - /* Byte alignment required. Check for overflow. */ - if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) - > xWantedSize ) + /* The wanted size must be increased so it can contain a BlockLink_t + * structure in addition to the requested amount of bytes. */ + if( ( xWantedSize > 0 ) && + ( ( xWantedSize + heapSTRUCT_SIZE ) > xWantedSize ) ) /* Overflow check */ { - xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); - configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 ); + xWantedSize += heapSTRUCT_SIZE; + + /* Byte alignment required. Check for overflow. */ + if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) + > xWantedSize ) + { + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 ); + } + else + { + xWantedSize = 0; + } } else { xWantedSize = 0; } - } - else - { - xWantedSize = 0; - } - if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) - { - /* Blocks are stored in byte order - traverse the list from the start - * (smallest) block until one of adequate size is found. */ - pxPreviousBlock = &xStart; - pxBlock = xStart.pxNextFreeBlock; - - while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) - { - pxPreviousBlock = pxBlock; - pxBlock = pxBlock->pxNextFreeBlock; - } - - /* If we found the end marker then a block of adequate size was not found. */ - if( pxBlock != &xEnd ) + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) { - /* Return the memory space - jumping over the BlockLink_t structure - * at its start. */ - pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); + /* Blocks are stored in byte order - traverse the list from the start + * (smallest) block until one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; - /* This block is being returned for use so must be taken out of the - * list of free blocks. */ - pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; - - /* If the block is larger than required it can be split into two. */ - if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) { - /* This block is to be split into two. Create a new block - * following the number of bytes requested. The void cast is - * used to prevent byte alignment warnings from the compiler. */ - pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); - - /* Calculate the sizes of two blocks split from the single - * block. */ - pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; - pxBlock->xBlockSize = xWantedSize; - - /* Insert the new block into the list of free blocks. */ - prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; } - xFreeBytesRemaining -= pxBlock->xBlockSize; + /* If we found the end marker then a block of adequate size was not found. */ + if( pxBlock != &xEnd ) + { + /* Return the memory space - jumping over the BlockLink_t structure + * at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); + + /* This block is being returned for use so must be taken out of the + * list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new block + * following the number of bytes requested. The void cast is + * used to prevent byte alignment warnings from the compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); + + /* Calculate the sizes of two blocks split from the single + * block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + + xFreeBytesRemaining -= pxBlock->xBlockSize; + + /* The block is being returned - it is allocated and owned + * by the application and has no "next" block. */ + heapALLOCATE_BLOCK( pxBlock ); + pxBlock->pxNextFreeBlock = NULL; + } } } @@ -235,14 +274,32 @@ void vPortFree( void * pv ) * byte alignment warnings. */ pxLink = ( void * ) puc; - vTaskSuspendAll(); + configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) ); + configASSERT( pxLink->pxNextFreeBlock == NULL ); + + if( heapBLOCK_IS_ALLOCATED( pxLink ) ) { - /* Add this block to the list of free blocks. */ - prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); - xFreeBytesRemaining += pxLink->xBlockSize; - traceFREE( pv, pxLink->xBlockSize ); + if( pxLink->pxNextFreeBlock == NULL ) + { + /* The block is being returned to the heap - it is no longer + * allocated. */ + heapFREE_BLOCK( pxLink ); + #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 ) + { + ( void ) memset( puc + heapSTRUCT_SIZE, 0, pxLink->xBlockSize - heapSTRUCT_SIZE ); + } + #endif + + vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + xFreeBytesRemaining += pxLink->xBlockSize; + traceFREE( pv, pxLink->xBlockSize ); + } + ( void ) xTaskResumeAll(); + } } - ( void ) xTaskResumeAll(); } } /*-----------------------------------------------------------*/ @@ -259,7 +316,27 @@ void vPortInitialiseBlocks( void ) } /*-----------------------------------------------------------*/ -static void prvHeapInit( void ) +void * pvPortCalloc( size_t xNum, + size_t xSize ) +{ + void * pv = NULL; + const size_t xSizeMaxValue = ~( ( size_t ) 0 ); + + if( !heapMULTIPLY_WILL_OVERFLOW( xNum, xSize, xSizeMaxValue ) ) + { + pv = pvPortMalloc( xNum * xSize ); + + if( pv != NULL ) + { + ( void ) memset( pv, 0, xNum * xSize ); + } + } + + return pv; +} +/*-----------------------------------------------------------*/ + +static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */ { BlockLink_t * pxFirstFreeBlock; uint8_t * pucAlignedHeap; diff --git a/portable/MemMang/heap_4.c b/portable/MemMang/heap_4.c index 79f666690..2ef538106 100644 --- a/portable/MemMang/heap_4.c +++ b/portable/MemMang/heap_4.c @@ -35,6 +35,7 @@ * memory management pages of https://www.FreeRTOS.org for more information. */ #include +#include /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining * all the API functions to use the MPU wrappers. That should only be done when @@ -50,12 +51,31 @@ #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 #endif +#ifndef configHEAP_CLEAR_MEMORY_ON_FREE + #define configHEAP_CLEAR_MEMORY_ON_FREE 0 +#endif + /* Block sizes must not get too small. */ #define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) ) /* Assumes 8bit bytes! */ #define heapBITS_PER_BYTE ( ( size_t ) 8 ) +/* Check if multiplying a and b will result in overflow. */ +#define heapMULTIPLY_WILL_OVERFLOW( a, b, max ) ( ( ( a ) > 0 ) && ( ( b ) > ( ( max ) / ( a ) ) ) ) + +/* MSB of the xBlockSize member of an BlockLink_t structure is used to track + * the allocation status of a block. When MSB of the xBlockSize member of + * an BlockLink_t structure is set then the block belongs to the application. + * When the bit is free the block is still part of the free heap space. */ +#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) ) +#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 ) +#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 ) +#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK ) +#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK ) + +/*-----------------------------------------------------------*/ + /* Allocate the memory for the heap. */ #if ( configAPPLICATION_ALLOCATED_HEAP == 1 ) @@ -106,12 +126,6 @@ PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = 0U; PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = 0; PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = 0; -/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize - * member of an BlockLink_t structure is set then the block belongs to the - * application. When the bit is free the block is still part of the free heap - * space. */ -PRIVILEGED_DATA static size_t xBlockAllocatedBit = 0; - /*-----------------------------------------------------------*/ void * pvPortMalloc( size_t xWantedSize ) @@ -136,7 +150,7 @@ void * pvPortMalloc( size_t xWantedSize ) * 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( heapBLOCK_SIZE_IS_VALID( xWantedSize ) ) { /* The wanted size must be increased so it can contain a BlockLink_t * structure in addition to the requested amount of bytes. */ @@ -232,7 +246,7 @@ void * pvPortMalloc( size_t xWantedSize ) /* The block is being returned - it is allocated and owned * by the application and has no "next" block. */ - pxBlock->xBlockSize |= xBlockAllocatedBit; + heapALLOCATE_BLOCK( pxBlock ); pxBlock->pxNextFreeBlock = NULL; xNumberOfSuccessfulAllocations++; } @@ -288,17 +302,21 @@ void vPortFree( void * pv ) /* This casting is to keep the compiler from issuing warnings. */ pxLink = ( void * ) puc; - /* Check the block is actually allocated. */ - configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) ); configASSERT( pxLink->pxNextFreeBlock == NULL ); - if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + if( heapBLOCK_IS_ALLOCATED( pxLink ) ) { if( pxLink->pxNextFreeBlock == NULL ) { /* The block is being returned to the heap - it is no longer * allocated. */ - pxLink->xBlockSize &= ~xBlockAllocatedBit; + heapFREE_BLOCK( pxLink ); + #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 ) + { + ( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize ); + } + #endif vTaskSuspendAll(); { @@ -341,6 +359,26 @@ void vPortInitialiseBlocks( void ) } /*-----------------------------------------------------------*/ +void * pvPortCalloc( size_t xNum, + size_t xSize ) +{ + void * pv = NULL; + const size_t xSizeMaxValue = ~( ( size_t ) 0 ); + + if( !heapMULTIPLY_WILL_OVERFLOW( xNum, xSize, xSizeMaxValue ) ) + { + pv = pvPortMalloc( xNum * xSize ); + + if( pv != NULL ) + { + ( void ) memset( pv, 0, xNum * xSize ); + } + } + + return pv; +} +/*-----------------------------------------------------------*/ + static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */ { BlockLink_t * pxFirstFreeBlock; @@ -383,9 +421,6 @@ static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */ /* Only one block exists - and it covers the entire usable heap space. */ xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; - - /* Work out the position of the top bit in a size_t variable. */ - xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); } /*-----------------------------------------------------------*/ @@ -502,3 +537,4 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats ) } taskEXIT_CRITICAL(); } +/*-----------------------------------------------------------*/ diff --git a/portable/MemMang/heap_5.c b/portable/MemMang/heap_5.c index c0d92edce..c12c95689 100644 --- a/portable/MemMang/heap_5.c +++ b/portable/MemMang/heap_5.c @@ -69,6 +69,7 @@ * */ #include +#include /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining * all the API functions to use the MPU wrappers. That should only be done when @@ -84,12 +85,31 @@ #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 #endif +#ifndef configHEAP_CLEAR_MEMORY_ON_FREE + #define configHEAP_CLEAR_MEMORY_ON_FREE 0 +#endif + /* Block sizes must not get too small. */ #define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) ) /* Assumes 8bit bytes! */ #define heapBITS_PER_BYTE ( ( size_t ) 8 ) +/* Check if multiplying a and b will result in overflow. */ +#define heapMULTIPLY_WILL_OVERFLOW( a, b, max ) ( ( ( a ) > 0 ) && ( ( b ) > ( ( max ) / ( a ) ) ) ) + +/* MSB of the xBlockSize member of an BlockLink_t structure is used to track + * the allocation status of a block. When MSB of the xBlockSize member of + * an BlockLink_t structure is set then the block belongs to the application. + * When the bit is free the block is still part of the free heap space. */ +#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) ) +#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 ) +#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 ) +#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK ) +#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK ) + +/*-----------------------------------------------------------*/ + /* Define the linked list structure. This is used to link free blocks in order * of their memory address. */ typedef struct A_BLOCK_LINK @@ -124,12 +144,6 @@ static size_t xMinimumEverFreeBytesRemaining = 0U; static size_t xNumberOfSuccessfulAllocations = 0; static size_t xNumberOfSuccessfulFrees = 0; -/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize - * member of an BlockLink_t structure is set then the block belongs to the - * application. When the bit is free the block is still part of the free heap - * space. */ -static size_t xBlockAllocatedBit = 0; - /*-----------------------------------------------------------*/ void * pvPortMalloc( size_t xWantedSize ) @@ -147,7 +161,7 @@ void * pvPortMalloc( size_t xWantedSize ) * 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( heapBLOCK_SIZE_IS_VALID( xWantedSize ) ) { /* The wanted size is increased so it can contain a BlockLink_t * structure in addition to the requested amount of bytes. */ @@ -241,7 +255,7 @@ void * pvPortMalloc( size_t xWantedSize ) /* The block is being returned - it is allocated and owned * by the application and has no "next" block. */ - pxBlock->xBlockSize |= xBlockAllocatedBit; + heapALLOCATE_BLOCK( pxBlock ); pxBlock->pxNextFreeBlock = NULL; xNumberOfSuccessfulAllocations++; } @@ -296,17 +310,21 @@ void vPortFree( void * pv ) /* This casting is to keep the compiler from issuing warnings. */ pxLink = ( void * ) puc; - /* Check the block is actually allocated. */ - configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) ); configASSERT( pxLink->pxNextFreeBlock == NULL ); - if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + if( heapBLOCK_IS_ALLOCATED( pxLink ) ) { if( pxLink->pxNextFreeBlock == NULL ) { /* The block is being returned to the heap - it is no longer * allocated. */ - pxLink->xBlockSize &= ~xBlockAllocatedBit; + heapFREE_BLOCK( pxLink ); + #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 ) + { + ( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize ); + } + #endif vTaskSuspendAll(); { @@ -343,6 +361,26 @@ size_t xPortGetMinimumEverFreeHeapSize( void ) } /*-----------------------------------------------------------*/ +void * pvPortCalloc( size_t xNum, + size_t xSize ) +{ + void * pv = NULL; + const size_t xSizeMaxValue = ~( ( size_t ) 0 ); + + if( !heapMULTIPLY_WILL_OVERFLOW( xNum, xSize, xSizeMaxValue ) ) + { + pv = pvPortMalloc( xNum * xSize ); + + if( pv != NULL ) + { + ( void ) memset( pv, 0, xNum * xSize ); + } + } + + return pv; +} +/*-----------------------------------------------------------*/ + static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) { BlockLink_t * pxIterator; @@ -495,9 +533,6 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* Check something was actually defined before it is accessed. */ configASSERT( xTotalHeapSize ); - - /* Work out the position of the top bit in a size_t variable. */ - xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); } /*-----------------------------------------------------------*/ @@ -557,3 +592,4 @@ void vPortGetHeapStats( HeapStats_t * pxHeapStats ) } taskEXIT_CRITICAL(); } +/*-----------------------------------------------------------*/