--- /dev/null
+/*\r
+ FreeRTOS V7.1.1 - Copyright (C) 2012 Real Time Engineers Ltd.\r
+\r
+\r
+ ***************************************************************************\r
+ * *\r
+ * FreeRTOS tutorial books are available in pdf and paperback. *\r
+ * Complete, revised, and edited pdf reference manuals are also *\r
+ * available. *\r
+ * *\r
+ * Purchasing FreeRTOS documentation will not only help you, by *\r
+ * ensuring you get running as quickly as possible and with an *\r
+ * in-depth knowledge of how to use FreeRTOS, it will also help *\r
+ * the FreeRTOS project to continue with its mission of providing *\r
+ * professional grade, cross platform, de facto standard solutions *\r
+ * for microcontrollers - completely free of charge! *\r
+ * *\r
+ * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *\r
+ * *\r
+ * Thank you for using FreeRTOS, and thank you for your support! *\r
+ * *\r
+ ***************************************************************************\r
+\r
+\r
+ This file is part of the FreeRTOS distribution.\r
+\r
+ FreeRTOS is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License (version 2) as published by the\r
+ Free Software Foundation AND MODIFIED BY the FreeRTOS exception.\r
+ >>>NOTE<<< The modification to the GPL is included to allow you to\r
+ distribute a combined work that includes FreeRTOS without being obliged to\r
+ provide the source code for proprietary components outside of the FreeRTOS\r
+ kernel. FreeRTOS is distributed in the hope that it will be useful, but\r
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\r
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\r
+ more details. You should have received a copy of the GNU General Public\r
+ License and the FreeRTOS license exception along with FreeRTOS; if not it\r
+ can be viewed here: http://www.freertos.org/a00114.html and also obtained\r
+ by writing to Richard Barry, contact details for whom are available on the\r
+ FreeRTOS WEB site.\r
+\r
+ 1 tab == 4 spaces!\r
+\r
+ ***************************************************************************\r
+ * *\r
+ * Having a problem? Start by reading the FAQ "My application does *\r
+ * not run, what could be wrong? *\r
+ * *\r
+ * http://www.FreeRTOS.org/FAQHelp.html *\r
+ * *\r
+ ***************************************************************************\r
+\r
+\r
+ http://www.FreeRTOS.org - Documentation, training, latest information,\r
+ license and contact details.\r
+\r
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
+ including FreeRTOS+Trace - an indispensable productivity tool.\r
+\r
+ Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell\r
+ the code with commercial support, indemnification, and middleware, under\r
+ the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also\r
+ provide a safety engineered and independently SIL3 certified version under\r
+ the SafeRTOS brand: http://www.SafeRTOS.com.\r
+*/\r
+\r
+/*\r
+ * A sample implementation of pvPortMalloc() and vPortFree() that combines \r
+ * (coalescences) adjacent memory blocks as they are freed, and in so doing \r
+ * limits memory fragmentation.\r
+ *\r
+ * See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the \r
+ * memory management pages of http://www.FreeRTOS.org for more information.\r
+ */\r
+#include <stdlib.h>\r
+\r
+/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
+all the API functions to use the MPU wrappers. That should only be done when\r
+task.h is included from an application file. */\r
+#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
+\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+\r
+#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
+\r
+/* Block sizes must not get too small. */\r
+#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )\r
+\r
+/* Allocate the memory for the heap. The struct is used to force byte\r
+alignment without using any non-portable code. */\r
+static union xRTOS_HEAP\r
+{\r
+ #if portBYTE_ALIGNMENT == 8\r
+ volatile portDOUBLE dDummy;\r
+ #else\r
+ volatile unsigned long ulDummy;\r
+ #endif\r
+ unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];\r
+} xHeap;\r
+\r
+/* Define the linked list structure. This is used to link free blocks in order\r
+of their memory address. */\r
+typedef struct A_BLOCK_LINK\r
+{\r
+ struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */\r
+ size_t xBlockSize; /*<< The size of the free block. */\r
+} xBlockLink;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * Inserts a block of memory that is being freed into the correct position in \r
+ * the list of free memory blocks. The block being freed will be merged with\r
+ * the block in front it and/or the block behind it if the memory blocks are\r
+ * adjacent to each other.\r
+ */\r
+static void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert );\r
+\r
+/*\r
+ * Called automatically to setup the required heap structures the first time\r
+ * pvPortMalloc() is called.\r
+ */\r
+static void prvHeapInit( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The size of the structure placed at the beginning of each allocated memory\r
+block must by correctly byte aligned. */\r
+static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );\r
+\r
+/* Ensure the pxEnd pointer will end up on the correct byte alignment. */\r
+static const size_t xTotalHeapSize = ( ( size_t ) configTOTAL_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\r
+\r
+/* Create a couple of list links to mark the start and end of the list. */\r
+static xBlockLink xStart, *pxEnd = NULL;\r
+\r
+/* Keeps track of the number of free bytes remaining, but says nothing about\r
+fragmentation. */\r
+static size_t xFreeBytesRemaining = ( ( size_t ) configTOTAL_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );\r
+\r
+/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void *pvPortMalloc( size_t xWantedSize )\r
+{\r
+xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;\r
+void *pvReturn = NULL;\r
+\r
+ vTaskSuspendAll();\r
+ {\r
+ /* If this is the first call to malloc then the heap will require\r
+ initialisation to setup the list of free blocks. */\r
+ if( pxEnd == NULL )\r
+ {\r
+ prvHeapInit();\r
+ }\r
+\r
+ /* The wanted size is increased so it can contain a xBlockLink\r
+ structure in addition to the requested amount of bytes. */\r
+ if( xWantedSize > 0 )\r
+ {\r
+ xWantedSize += heapSTRUCT_SIZE;\r
+\r
+ /* Ensure that blocks are always aligned to the required number of \r
+ bytes. */\r
+ if( xWantedSize & portBYTE_ALIGNMENT_MASK )\r
+ {\r
+ /* Byte alignment required. */\r
+ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );\r
+ }\r
+ }\r
+\r
+ if( ( xWantedSize > 0 ) && ( xWantedSize < xTotalHeapSize ) )\r
+ {\r
+ /* Traverse the list from the start (lowest address) block until one\r
+ of adequate size is found. */\r
+ pxPreviousBlock = &xStart;\r
+ pxBlock = xStart.pxNextFreeBlock;\r
+ while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )\r
+ {\r
+ pxPreviousBlock = pxBlock;\r
+ pxBlock = pxBlock->pxNextFreeBlock;\r
+ }\r
+\r
+ /* If the end marker was reached then a block of adequate size was\r
+ not found. */\r
+ if( pxBlock != pxEnd )\r
+ {\r
+ /* Return the memory space - jumping over the xBlockLink structure\r
+ at its start. */\r
+ pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );\r
+\r
+ /* This block is being returned for use so must be taken out of\r
+ the list of free blocks. */\r
+ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;\r
+\r
+ /* If the block is larger than required it can be split into two. */\r
+ if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )\r
+ {\r
+ /* This block is to be split into two. Create a new block\r
+ following the number of bytes requested. The void cast is\r
+ used to prevent byte alignment warnings from the compiler. */\r
+ pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );\r
+\r
+ /* Calculate the sizes of two blocks split from the single\r
+ block. */\r
+ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;\r
+ pxBlock->xBlockSize = xWantedSize;\r
+\r
+ /* Insert the new block into the list of free blocks. */\r
+ prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );\r
+ }\r
+\r
+ xFreeBytesRemaining -= pxBlock->xBlockSize;\r
+ }\r
+ }\r
+ }\r
+ xTaskResumeAll();\r
+\r
+ #if( configUSE_MALLOC_FAILED_HOOK == 1 )\r
+ {\r
+ if( pvReturn == NULL )\r
+ {\r
+ extern void vApplicationMallocFailedHook( void );\r
+ vApplicationMallocFailedHook();\r
+ }\r
+ }\r
+ #endif\r
+\r
+ return pvReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortFree( void *pv )\r
+{\r
+unsigned char *puc = ( unsigned char * ) pv;\r
+xBlockLink *pxLink;\r
+\r
+ if( pv != NULL )\r
+ {\r
+ /* The memory being freed will have an xBlockLink structure immediately\r
+ before it. */\r
+ puc -= heapSTRUCT_SIZE;\r
+\r
+ /* This casting is to keep the compiler from issuing warnings. */\r
+ pxLink = ( void * ) puc;\r
+\r
+ vTaskSuspendAll();\r
+ {\r
+ /* Add this block to the list of free blocks. */\r
+ xFreeBytesRemaining += pxLink->xBlockSize;\r
+ prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) ); \r
+ }\r
+ xTaskResumeAll();\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+size_t xPortGetFreeHeapSize( void )\r
+{\r
+ return xFreeBytesRemaining;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vPortInitialiseBlocks( void )\r
+{\r
+ /* This just exists to keep the linker quiet. */\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvHeapInit( void )\r
+{\r
+xBlockLink *pxFirstFreeBlock;\r
+unsigned char *pucHeapEnd;\r
+\r
+ /* Ensure the start of the heap is aligned. */\r
+ configASSERT( ( ( ( unsigned long ) xHeap.ucHeap ) & ( ( unsigned long ) portBYTE_ALIGNMENT_MASK ) ) == 0UL );\r
+\r
+ /* xStart is used to hold a pointer to the first item in the list of free\r
+ blocks. The void cast is used to prevent compiler warnings. */\r
+ xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap;\r
+ xStart.xBlockSize = ( size_t ) 0;\r
+\r
+ /* pxEnd is used to mark the end of the list of free blocks and is inserted\r
+ at the end of the heap space. */\r
+ pucHeapEnd = xHeap.ucHeap + xTotalHeapSize;\r
+ pucHeapEnd -= heapSTRUCT_SIZE;\r
+ pxEnd = ( void * ) pucHeapEnd;\r
+ configASSERT( ( ( ( unsigned long ) pxEnd ) & ( ( unsigned long ) portBYTE_ALIGNMENT_MASK ) ) == 0UL );\r
+ pxEnd->xBlockSize = 0;\r
+ pxEnd->pxNextFreeBlock = NULL;\r
+\r
+ /* To start with there is a single free block that is sized to take up the\r
+ entire heap space, minus the space taken by pxEnd. */\r
+ pxFirstFreeBlock = ( void * ) xHeap.ucHeap;\r
+ pxFirstFreeBlock->xBlockSize = xTotalHeapSize - heapSTRUCT_SIZE;\r
+ pxFirstFreeBlock->pxNextFreeBlock = pxEnd;\r
+\r
+ /* The heap now contains pxEnd. */\r
+ xFreeBytesRemaining -= heapSTRUCT_SIZE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvInsertBlockIntoFreeList( xBlockLink *pxBlockToInsert )\r
+{\r
+xBlockLink *pxIterator;\r
+unsigned char *puc;\r
+\r
+ /* Iterate through the list until a block is found that has a higher address\r
+ than the block being inserted. */\r
+ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )\r
+ {\r
+ /* Nothing to do here, just iterate to the right position. */\r
+ }\r
+\r
+ /* Do the block being inserted, and the block it is being inserted after\r
+ make a contiguous block of memory? */ \r
+ puc = ( unsigned char * ) pxIterator;\r
+ if( ( puc + pxIterator->xBlockSize ) == ( unsigned char * ) pxBlockToInsert )\r
+ {\r
+ pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;\r
+ pxBlockToInsert = pxIterator;\r
+ }\r
+\r
+ /* Do the block being inserted, and the block it is being inserted before\r
+ make a contiguous block of memory? */\r
+ puc = ( unsigned char * ) pxBlockToInsert;\r
+ if( ( puc + pxBlockToInsert->xBlockSize ) == ( unsigned char * ) pxIterator->pxNextFreeBlock )\r
+ {\r
+ if( pxIterator->pxNextFreeBlock != pxEnd )\r
+ {\r
+ /* Form one big block from the two blocks. */\r
+ pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;\r
+ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;\r
+ }\r
+ else\r
+ {\r
+ pxBlockToInsert->pxNextFreeBlock = pxEnd;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \r
+ }\r
+\r
+ /* If the block being inserted plugged a gab, so was merged with the block\r
+ before and the block after, then it's pxNextFreeBlock pointer will have\r
+ already been set, and should not be set here as that would make it point\r
+ to itself. */\r
+ if( pxIterator != pxBlockToInsert )\r
+ {\r
+ pxIterator->pxNextFreeBlock = pxBlockToInsert;\r
+ }\r
+}\r
+\r
+\r
+#define INCLUDE_TEST_CODE 1\r
+#if INCLUDE_TEST_CODE == 1\r
+\r
+#define heapMAX_TEST_BLOCKS 6\r
+\r
+void vTestHeap4( void )\r
+{\r
+void *pvReturned;\r
+static void *pvUsedBlocks[ heapMAX_TEST_BLOCKS ];\r
+unsigned long ulIndex = 0, ulSize, ulRandSample;\r
+static const unsigned long ulCombinations[ 6 ][ 3 ] =\r
+{\r
+ { 0, 1, 2 },\r
+ { 0, 2, 1 },\r
+ { 1, 0, 2 },\r
+ { 1, 2, 0 },\r
+ { 2, 0, 1 },\r
+ { 2, 1, 0 }\r
+};\r
+\r
+ /* Attempt to obtain a block of memory that equals the enture heap size.\r
+ This should fail as the size of a block link structure will be added to the\r
+ block in pvPortMalloc(). */\r
+ pvReturned = pvPortMalloc( xTotalHeapSize );\r
+ configASSERT( pvReturned == NULL );\r
+\r
+ /* Attempt to obtain a block of memory that equals the entire heap size \r
+ minus the size of the block link structure that will get added to the \r
+ wanted size inside pvPortMalloc(). This should also fail as the heap \r
+ already contains a start and end block link structure. */\r
+ pvReturned = pvPortMalloc( xTotalHeapSize - heapSTRUCT_SIZE );\r
+ configASSERT( pvReturned == NULL );\r
+\r
+ /* Attempt to obtain a block of memory that equals the entire heap size \r
+ minus the size of the block link structure that will get added to the \r
+ wanted size inside pvPortMalloc(), minus the size of the block link \r
+ structure that marks the end of the heap. */\r
+ pvReturned = pvPortMalloc( xTotalHeapSize - ( 2 * heapSTRUCT_SIZE ) );\r
+\r
+ /* The returned value should point just past the first block link. */\r
+ configASSERT( pvReturned == ( xHeap.ucHeap + heapSTRUCT_SIZE ) );\r
+\r
+ /* There should be no heap remaining. */\r
+ configASSERT( xFreeBytesRemaining == 0 );\r
+\r
+ /* The start should point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock == pxEnd );\r
+\r
+ /* Free the memory again. */\r
+ vPortFree( pvReturned );\r
+\r
+ /* The heap should be back to its full size, which is the total bytes\r
+ in the array minus the space taken up by the pxEnd structure. */\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+\r
+ /* The start block should now point to a block that holds the entire heap\r
+ space, which should itself point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock->xBlockSize == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+ configASSERT( xStart.pxNextFreeBlock->pxNextFreeBlock == pxEnd );\r
+\r
+ /* The next test plugs a gap that create a continuous block up to the pxEnd\r
+ marker. */\r
+\r
+ /* Remove a small block. */\r
+ pvUsedBlocks[ ulIndex ] = pvPortMalloc( 8 );\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE - 8 - heapSTRUCT_SIZE ) );\r
+ ulIndex++;\r
+\r
+ /* Remove another block. */\r
+ pvUsedBlocks[ ulIndex ] = pvPortMalloc( 32 );\r
+\r
+ /* Return the frist removed block, which should join with the start block\r
+ and leave a gap. */\r
+ vPortFree( pvUsedBlocks[ 0 ] );\r
+ \r
+ /* Return the second free block, which should fill the gap. */\r
+ vPortFree( pvUsedBlocks[ 1 ] );\r
+\r
+ /* The heap should be back to its full size, which is the total bytes\r
+ in the array minus the space taken up by the pxEnd structure. */\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+\r
+ /* The start block should now point to a block that holds the entire heap\r
+ space, which should itself point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock->xBlockSize == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+ configASSERT( xStart.pxNextFreeBlock->pxNextFreeBlock == pxEnd );\r
+\r
+ /* The next test plugs a gap that create a continuous block but not up to\r
+ the end marker - it then fills the last gap too. */\r
+\r
+ ulIndex = 0;\r
+\r
+ /* Remove a small block. */\r
+ pvUsedBlocks[ ulIndex ] = pvPortMalloc( 8 );\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE - 8 - heapSTRUCT_SIZE ) );\r
+ ulIndex++;\r
+\r
+ /* Remove another block. */\r
+ pvUsedBlocks[ ulIndex ] = pvPortMalloc( 32 );\r
+ ulIndex++;\r
+\r
+ /* And one final block. */\r
+ pvUsedBlocks[ ulIndex ] = pvPortMalloc( 128 );\r
+\r
+ /* Return the frist removed block, which should join with the start block\r
+ and leave a gap. */\r
+ vPortFree( pvUsedBlocks[ 0 ] );\r
+\r
+ /* Return the last block, which should join with the end. */\r
+ vPortFree( pvUsedBlocks[ 2 ] );\r
+ \r
+ /* Return the middle block block, which should fill the gap. */\r
+ vPortFree( pvUsedBlocks[ 1 ] );\r
+\r
+ /* The heap should be back to its full size, which is the total bytes\r
+ in the array minus the space taken up by the pxEnd structure. */\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+\r
+ /* The start block should now point to a block that holds the entire heap\r
+ space, which should itself point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock->xBlockSize == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+ configASSERT( xStart.pxNextFreeBlock->pxNextFreeBlock == pxEnd );\r
+\r
+ for( ulIndex = 0; ulIndex < 6; ulIndex++ )\r
+ {\r
+ pvUsedBlocks[ 0 ] = pvPortMalloc( 10 );\r
+ pvUsedBlocks[ 1 ] = pvPortMalloc( 1 );\r
+ pvUsedBlocks[ 2 ] = pvPortMalloc( 10000 );\r
+\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 0 ] ] );\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 1 ] ] );\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 2 ] ] );\r
+\r
+ /* The heap should be back to its full size, which is the total bytes\r
+ in the array minus the space taken up by the pxEnd structure. */\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+\r
+ /* The start block should now point to a block that holds the entire heap\r
+ space, which should itself point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock->xBlockSize == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+ configASSERT( xStart.pxNextFreeBlock->pxNextFreeBlock == pxEnd );\r
+ }\r
+\r
+ /* Do the same, but using the entire block of memory. */\r
+ for( ulIndex = 0; ulIndex < 6; ulIndex++ )\r
+ {\r
+ /* Total heap size. */\r
+ ulSize = xTotalHeapSize - heapSTRUCT_SIZE;\r
+\r
+ /* Minus 4 heap structs (three allocated blocks plus pxEnd. */\r
+ ulSize -= 4 * heapSTRUCT_SIZE;\r
+\r
+ pvUsedBlocks[ 0 ] = pvPortMalloc( ulSize / 3 );\r
+ pvUsedBlocks[ 1 ] = pvPortMalloc( ulSize / 3 );\r
+ /* The last block includes any remainder. */\r
+ pvUsedBlocks[ 2 ] = pvPortMalloc( ( ulSize / 3 ) + ( ulSize % 3 ) );\r
+ configASSERT( pvUsedBlocks[ 2 ] ); \r
+ configASSERT( xFreeBytesRemaining == 0 );\r
+\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 0 ] ] );\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 1 ] ] );\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 2 ] ] );\r
+\r
+ /* The heap should be back to its full size, which is the total bytes\r
+ in the array minus the space taken up by the pxEnd structure. */\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+\r
+ /* The start block should now point to a block that holds the entire heap\r
+ space, which should itself point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock->xBlockSize == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+ configASSERT( xStart.pxNextFreeBlock->pxNextFreeBlock == pxEnd );\r
+ }\r
+\r
+ /* Do the same, but using random block sizes. */\r
+ for( ulRandSample = 0; ulRandSample < 0x5ffff; ulRandSample++ )\r
+ {\r
+ for( ulIndex = 0; ulIndex < 6; ulIndex++ )\r
+ {\r
+ pvUsedBlocks[ 0 ] = pvPortMalloc( rand() );\r
+ pvUsedBlocks[ 1 ] = pvPortMalloc( rand() );\r
+ pvUsedBlocks[ 2 ] = pvPortMalloc( rand() );\r
+\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 0 ] ] );\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 1 ] ] );\r
+ vPortFree( pvUsedBlocks[ ulCombinations[ ulIndex ][ 2 ] ] );\r
+\r
+ /* The heap should be back to its full size, which is the total bytes\r
+ in the array minus the space taken up by the pxEnd structure. */\r
+ configASSERT( xFreeBytesRemaining == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+\r
+ /* The start block should now point to a block that holds the entire heap\r
+ space, which should itself point to the end. */\r
+ configASSERT( xStart.pxNextFreeBlock->xBlockSize == ( xTotalHeapSize - heapSTRUCT_SIZE ) );\r
+ configASSERT( xStart.pxNextFreeBlock->pxNextFreeBlock == pxEnd );\r
+ }\r
+ }\r
+\r
+/* Particularly test the case where the block being inserted fills a gap \r
+requiring both the block in front and the block behind to be merged into one. */\r
+}\r
+\r
+#endif INCLUDE_TEST_CODE\r