Przeglądaj źródła

Port heap (#7)

* Port heap

* Use RT_KERNEL_MALLOC/FREE
tangzz98 3 lat temu
rodzic
commit
0a343dcbd2

+ 1 - 0
FreeRTOS/SConscript

@@ -4,6 +4,7 @@ from building import *
 cwd = GetCurrentDir()
 src	= Glob('*.c')
 src += Glob(os.path.join("portable", "rt-thread", "*.c"))
+src += Glob(os.path.join("portable", "MemMang", "heap_3.c"))
 
 CPPPATH = [os.path.join(cwd, "include"), os.path.join(cwd, "portable", "rt-thread")]
 

+ 3 - 3
FreeRTOS/include/FreeRTOSConfig.h

@@ -50,16 +50,13 @@
 #define configTICK_RATE_HZ                      ( 1000 )
 #define configMAX_PRIORITIES                    ( 5 )
 #define configMINIMAL_STACK_SIZE                ( ( unsigned short ) 130 )
-#define configTOTAL_HEAP_SIZE                   ( ( size_t ) ( 46 * 1024 ) )
 #define configMAX_TASK_NAME_LEN                 ( 10 )
 #define configUSE_TRACE_FACILITY                1
 #define configUSE_16_BIT_TICKS                  0
 #define configIDLE_SHOULD_YIELD                 1
 #define configQUEUE_REGISTRY_SIZE               8
 #define configCHECK_FOR_STACK_OVERFLOW          2
-#define configUSE_MALLOC_FAILED_HOOK            1
 #define configUSE_APPLICATION_TASK_TAG          0
-#define configUSE_COUNTING_SEMAPHORES           1
 
 /* The full demo always has tasks to run so the tick will never be turned off.
 The blinky demo will use the default tickless idle implementation to turn the
@@ -133,5 +130,8 @@ standard names. */
 #define configSUPPORT_DYNAMIC_ALLOCATION        1
 #define configSUPPORT_STATIC_ALLOCATION         1
 #define configUSE_RECURSIVE_MUTEXES             1
+#define configTOTAL_HEAP_SIZE                   ( ( size_t ) ( 46 * 1024 ) )
+#define configUSE_COUNTING_SEMAPHORES           1
+#define configUSE_MALLOC_FAILED_HOOK            0
 
 #endif /* FREERTOS_CONFIG_H */

+ 72 - 0
FreeRTOS/include/portable.h

@@ -35,12 +35,84 @@
 
 #include "portmacro.h"
 
+#if portBYTE_ALIGNMENT == 32
+    #define portBYTE_ALIGNMENT_MASK    ( 0x001f )
+#elif portBYTE_ALIGNMENT == 16
+    #define portBYTE_ALIGNMENT_MASK    ( 0x000f )
+#elif portBYTE_ALIGNMENT == 8
+    #define portBYTE_ALIGNMENT_MASK    ( 0x0007 )
+#elif portBYTE_ALIGNMENT == 4
+    #define portBYTE_ALIGNMENT_MASK    ( 0x0003 )
+#elif portBYTE_ALIGNMENT == 2
+    #define portBYTE_ALIGNMENT_MASK    ( 0x0001 )
+#elif portBYTE_ALIGNMENT == 1
+    #define portBYTE_ALIGNMENT_MASK    ( 0x0000 )
+#else /* if portBYTE_ALIGNMENT == 32 */
+    #error "Invalid portBYTE_ALIGNMENT definition"
+#endif /* if portBYTE_ALIGNMENT == 32 */
+
 /* *INDENT-OFF* */
 #ifdef __cplusplus
     extern "C" {
 #endif
 /* *INDENT-ON* */
 
+/* Used by heap_5.c to define the start address and size of each memory region
+ * that together comprise the total FreeRTOS heap space. */
+typedef struct HeapRegion
+{
+    uint8_t * pucStartAddress;
+    size_t xSizeInBytes;
+} HeapRegion_t;
+
+/* Used to pass information about the heap out of vPortGetHeapStats(). */
+typedef struct xHeapStats
+{
+    size_t xAvailableHeapSpaceInBytes;      /* The total heap size currently available - this is the sum of all the free blocks, not the largest block that can be allocated. */
+    size_t xSizeOfLargestFreeBlockInBytes;  /* The maximum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */
+    size_t xSizeOfSmallestFreeBlockInBytes; /* The minimum size, in bytes, of all the free blocks within the heap at the time vPortGetHeapStats() is called. */
+    size_t xNumberOfFreeBlocks;             /* The number of free memory blocks within the heap at the time vPortGetHeapStats() is called. */
+    size_t xMinimumEverFreeBytesRemaining;  /* The minimum amount of total free memory (sum of all free blocks) there has been in the heap since the system booted. */
+    size_t xNumberOfSuccessfulAllocations;  /* The number of calls to pvPortMalloc() that have returned a valid memory block. */
+    size_t xNumberOfSuccessfulFrees;        /* The number of calls to vPortFree() that has successfully freed a block of memory. */
+} HeapStats_t;
+
+/*
+ * Used to define multiple heap regions for use by heap_5.c.  This function
+ * must be called before any calls to pvPortMalloc() - not creating a task,
+ * queue, semaphore, mutex, software timer, event group, etc. will result in
+ * pvPortMalloc being called.
+ *
+ * pxHeapRegions passes in an array of HeapRegion_t structures - each of which
+ * defines a region of memory that can be used as the heap.  The array is
+ * terminated by a HeapRegions_t structure that has a size of 0.  The region
+ * with the lowest start address must appear first in the array.
+ */
+void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions );
+
+/*
+ * Returns a HeapStats_t structure filled with information about the current
+ * heap state.
+ */
+void vPortGetHeapStats( HeapStats_t * pxHeapStats );
+
+/*
+ * Map to the memory management routines required for the port.
+ */
+void * pvPortMalloc( size_t xSize );
+void vPortFree( void * pv );
+void vPortInitialiseBlocks( void );
+size_t xPortGetFreeHeapSize( void );
+size_t xPortGetMinimumEverFreeHeapSize( void );
+
+#if ( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 )
+    void * pvPortMallocStack( size_t xSize );
+    void vPortFreeStack( void * pv );
+#else
+    #define pvPortMallocStack    pvPortMalloc
+    #define vPortFreeStack       vPortFree
+#endif
+
 BaseType_t rt_err_to_freertos(rt_err_t rt_err);
 
 /* *INDENT-OFF* */

+ 227 - 0
FreeRTOS/include/task.h

@@ -0,0 +1,227 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+
+#ifndef INC_TASK_H
+#define INC_TASK_H
+
+#ifndef INC_FREERTOS_H
+    #error "include FreeRTOS.h must appear in source files before include task.h"
+#endif
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+    extern "C" {
+#endif
+/* *INDENT-ON* */
+
+/*-----------------------------------------------------------
+* MACROS AND DEFINITIONS
+*----------------------------------------------------------*/
+
+/*
+ * If tskKERNEL_VERSION_NUMBER ends with + it represents the version in development
+ * after the numbered release.
+ *
+ * The tskKERNEL_VERSION_MAJOR, tskKERNEL_VERSION_MINOR, tskKERNEL_VERSION_BUILD
+ * values will reflect the last released version number.
+ */
+#define tskKERNEL_VERSION_NUMBER       "V10.4.6"
+#define tskKERNEL_VERSION_MAJOR        10
+#define tskKERNEL_VERSION_MINOR        4
+#define tskKERNEL_VERSION_BUILD        6
+
+/**
+ * task. h
+ *
+ * Macro to mark the start of a critical code region.  Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \defgroup taskENTER_CRITICAL taskENTER_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskENTER_CRITICAL()               portENTER_CRITICAL()
+#define taskENTER_CRITICAL_FROM_ISR()      portSET_INTERRUPT_MASK_FROM_ISR()
+
+/**
+ * task. h
+ *
+ * Macro to mark the end of a critical code region.  Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \defgroup taskEXIT_CRITICAL taskEXIT_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskEXIT_CRITICAL()                portEXIT_CRITICAL()
+#define taskEXIT_CRITICAL_FROM_ISR( x )    portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
+
+/**
+ * task. h
+ *
+ * Macro to disable all maskable interrupts.
+ *
+ * \defgroup taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskDISABLE_INTERRUPTS()           portDISABLE_INTERRUPTS()
+
+/**
+ * task. h
+ *
+ * Macro to enable microcontroller interrupts.
+ *
+ * \defgroup taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskENABLE_INTERRUPTS()            portENABLE_INTERRUPTS()
+
+/*-----------------------------------------------------------
+* SCHEDULER CONTROL
+*----------------------------------------------------------*/
+
+/**
+ * task. h
+ * @code{c}
+ * void vTaskSuspendAll( void );
+ * @endcode
+ *
+ * Suspends the scheduler without disabling interrupts.  Context switches will
+ * not occur while the scheduler is suspended.
+ *
+ * After calling vTaskSuspendAll () the calling task will continue to execute
+ * without risk of being swapped out until a call to xTaskResumeAll () has been
+ * made.
+ *
+ * API functions that have the potential to cause a context switch (for example,
+ * xTaskDelayUntil(), xQueueSend(), etc.) must not be called while the scheduler
+ * is suspended.
+ *
+ * Example usage:
+ * @code{c}
+ * void vTask1( void * pvParameters )
+ * {
+ *   for( ;; )
+ *   {
+ *       // Task code goes here.
+ *
+ *       // ...
+ *
+ *       // At some point the task wants to perform a long operation during
+ *       // which it does not want to get swapped out.  It cannot use
+ *       // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ *       // operation may cause interrupts to be missed - including the
+ *       // ticks.
+ *
+ *       // Prevent the real time kernel swapping out the task.
+ *       vTaskSuspendAll ();
+ *
+ *       // Perform the operation here.  There is no need to use critical
+ *       // sections as we have all the microcontroller processing time.
+ *       // During this time interrupts will still operate and the kernel
+ *       // tick count will be maintained.
+ *
+ *       // ...
+ *
+ *       // The operation is complete.  Restart the kernel.
+ *       xTaskResumeAll ();
+ *   }
+ * }
+ * @endcode
+ * \defgroup vTaskSuspendAll vTaskSuspendAll
+ * \ingroup SchedulerControl
+ */
+void vTaskSuspendAll( void );
+
+/**
+ * task. h
+ * @code{c}
+ * BaseType_t xTaskResumeAll( void );
+ * @endcode
+ *
+ * Resumes scheduler activity after it was suspended by a call to
+ * vTaskSuspendAll().
+ *
+ * xTaskResumeAll() only resumes the scheduler.  It does not unsuspend tasks
+ * that were previously suspended by a call to vTaskSuspend().
+ *
+ * @return If resuming the scheduler caused a context switch then pdTRUE is
+ *         returned, otherwise pdFALSE is returned.
+ *
+ * Example usage:
+ * @code{c}
+ * void vTask1( void * pvParameters )
+ * {
+ *   for( ;; )
+ *   {
+ *       // Task code goes here.
+ *
+ *       // ...
+ *
+ *       // At some point the task wants to perform a long operation during
+ *       // which it does not want to get swapped out.  It cannot use
+ *       // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ *       // operation may cause interrupts to be missed - including the
+ *       // ticks.
+ *
+ *       // Prevent the real time kernel swapping out the task.
+ *       vTaskSuspendAll ();
+ *
+ *       // Perform the operation here.  There is no need to use critical
+ *       // sections as we have all the microcontroller processing time.
+ *       // During this time interrupts will still operate and the real
+ *       // time kernel tick count will be maintained.
+ *
+ *       // ...
+ *
+ *       // The operation is complete.  Restart the kernel.  We want to force
+ *       // a context switch - but there is no point if resuming the scheduler
+ *       // caused a context switch already.
+ *       if( !xTaskResumeAll () )
+ *       {
+ *            taskYIELD ();
+ *       }
+ *   }
+ * }
+ * @endcode
+ * \defgroup xTaskResumeAll xTaskResumeAll
+ * \ingroup SchedulerControl
+ */
+BaseType_t xTaskResumeAll( void );
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+    }
+#endif
+/* *INDENT-ON* */
+#endif /* INC_TASK_H */

+ 145 - 0
FreeRTOS/portable/MemMang/heap_1.c

@@ -0,0 +1,145 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+
+/*
+ * The simplest possible implementation of pvPortMalloc().  Note that this
+ * implementation does NOT allow allocated memory to be freed again.
+ *
+ * See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the
+ * memory management pages of https://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
+    #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
+#endif
+
+/* A few bytes might be lost to byte aligning the heap start address. */
+#define configADJUSTED_HEAP_SIZE    ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
+
+/* Allocate the memory for the heap. */
+#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
+
+/* The application writer has already defined the array used for the RTOS
+* 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 ];
+#endif /* configAPPLICATION_ALLOCATED_HEAP */
+
+/* Index into the ucHeap array. */
+static size_t xNextFreeByte = ( size_t ) 0;
+
+/*-----------------------------------------------------------*/
+
+void * pvPortMalloc( size_t xWantedSize )
+{
+    void * pvReturn = NULL;
+    static uint8_t * pucAlignedHeap = NULL;
+
+    /* Ensure that blocks are always aligned. */
+    #if ( portBYTE_ALIGNMENT != 1 )
+        {
+            if( xWantedSize & portBYTE_ALIGNMENT_MASK )
+            {
+                /* Byte alignment required. Check for overflow. */
+                if ( (xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )) > xWantedSize )
+                {
+                    xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
+                }
+                else
+                {
+                    xWantedSize = 0;
+                }
+            }
+        }
+    #endif
+
+    vTaskSuspendAll();
+    {
+        if( pucAlignedHeap == NULL )
+        {
+            /* Ensure the heap starts on a correctly aligned boundary. */
+            pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
+        }
+
+        /* Check there is enough room left for the allocation and. */
+        if( ( xWantedSize > 0 ) && /* valid size */
+            ( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
+            ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) ) /* Check for overflow. */
+        {
+            /* Return the next free byte then increment the index past this
+             * block. */
+            pvReturn = pucAlignedHeap + xNextFreeByte;
+            xNextFreeByte += xWantedSize;
+        }
+
+    }
+    ( void ) xTaskResumeAll();
+
+    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
+        {
+            if( pvReturn == NULL )
+            {
+                extern void vApplicationMallocFailedHook( void );
+                vApplicationMallocFailedHook();
+            }
+        }
+    #endif
+
+    return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void * pv )
+{
+    /* Memory cannot be freed using this scheme.  See heap_2.c, heap_3.c and
+     * heap_4.c for alternative implementations, and the memory management pages of
+     * https://www.FreeRTOS.org for more information. */
+    ( void ) pv;
+
+    /* Force an assert as it is invalid to call this function. */
+    configASSERT( pv == NULL );
+}
+/*-----------------------------------------------------------*/
+
+void vPortInitialiseBlocks( void )
+{
+    /* Only required when static memory is not cleared. */
+    xNextFreeByte = ( size_t ) 0;
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetFreeHeapSize( void )
+{
+    return( configADJUSTED_HEAP_SIZE - xNextFreeByte );
+}

+ 277 - 0
FreeRTOS/portable/MemMang/heap_2.c

@@ -0,0 +1,277 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/*
+ * A sample implementation of pvPortMalloc() and vPortFree() that permits
+ * allocated blocks to be freed, but does not combine adjacent free blocks
+ * into a single larger block (and so will fragment memory).  See heap_4.c for
+ * an equivalent that does combine adjacent blocks into single larger blocks.
+ *
+ * See heap_1.c, heap_3.c and heap_4.c for alternative implementations, and the
+ * memory management pages of https://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
+    #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 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 );
+
+/* Allocate the memory for the heap. */
+#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
+
+/* The application writer has already defined the array used for the RTOS
+* 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 ];
+#endif /* configAPPLICATION_ALLOCATED_HEAP */
+
+
+/* Define the linked list structure.  This is used to link free blocks in order
+ * of their size. */
+typedef struct A_BLOCK_LINK
+{
+    struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
+    size_t xBlockSize;                     /*<< The size of the free block. */
+} BlockLink_t;
+
+
+static const uint16_t heapSTRUCT_SIZE = ( ( sizeof( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
+#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;
+
+/* Keeps track of the number of free bytes remaining, but says nothing about
+ * fragmentation. */
+static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;
+
+/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
+
+/*
+ * Insert a block into the list of free blocks - which is ordered by size of
+ * the block.  Small blocks at the start of the list and large blocks at the end
+ * of the list.
+ */
+#define prvInsertBlockIntoFreeList( pxBlockToInsert )                                                                               \
+    {                                                                                                                               \
+        BlockLink_t * pxIterator;                                                                                                   \
+        size_t xBlockSize;                                                                                                          \
+                                                                                                                                    \
+        xBlockSize = pxBlockToInsert->xBlockSize;                                                                                   \
+                                                                                                                                    \
+        /* Iterate through the list until a block is found that has a larger size */                                                \
+        /* than the block we are inserting. */                                                                                      \
+        for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
+        {                                                                                                                           \
+            /* There is nothing to do here - just iterate to the correct position. */                                               \
+        }                                                                                                                           \
+                                                                                                                                    \
+        /* Update the list to include the block being inserted in the correct */                                                    \
+        /* position. */                                                                                                             \
+        pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;                                                             \
+        pxIterator->pxNextFreeBlock = pxBlockToInsert;                                                                              \
+    }
+/*-----------------------------------------------------------*/
+
+void * pvPortMalloc( size_t xWantedSize )
+{
+    BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
+    static BaseType_t xHeapHasBeenInitialised = pdFALSE;
+    void * pvReturn = NULL;
+
+    vTaskSuspendAll();
+    {
+        /* If this is the first call to malloc then the heap will require
+         * initialisation to setup the list of free blocks. */
+        if( xHeapHasBeenInitialised == pdFALSE )
+        {
+            prvHeapInit();
+            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 */
+        {
+            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;
+        }
+
+
+        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 )
+            {
+                /* 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;
+            }
+        }
+
+    }
+    ( void ) xTaskResumeAll();
+
+    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
+        {
+            if( pvReturn == NULL )
+            {
+                extern void vApplicationMallocFailedHook( void );
+                vApplicationMallocFailedHook();
+            }
+        }
+    #endif
+
+    return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void * pv )
+{
+    uint8_t * puc = ( uint8_t * ) pv;
+    BlockLink_t * pxLink;
+
+    if( pv != NULL )
+    {
+        /* The memory being freed will have an BlockLink_t structure immediately
+         * before it. */
+        puc -= heapSTRUCT_SIZE;
+
+        /* This unexpected casting is to keep some compilers from issuing
+         * byte alignment warnings. */
+        pxLink = ( void * ) puc;
+
+        vTaskSuspendAll();
+        {
+            /* Add this block to the list of free blocks. */
+            prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
+            xFreeBytesRemaining += pxLink->xBlockSize;
+        }
+        ( void ) xTaskResumeAll();
+    }
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetFreeHeapSize( void )
+{
+    return xFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+void vPortInitialiseBlocks( void )
+{
+    /* This just exists to keep the linker quiet. */
+}
+/*-----------------------------------------------------------*/
+
+static void prvHeapInit( void )
+{
+    BlockLink_t * pxFirstFreeBlock;
+    uint8_t * pucAlignedHeap;
+
+    /* Ensure the heap starts on a correctly aligned boundary. */
+    pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
+
+    /* xStart is used to hold a pointer to the first item in the list of free
+     * blocks.  The void cast is used to prevent compiler warnings. */
+    xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
+    xStart.xBlockSize = ( size_t ) 0;
+
+    /* xEnd is used to mark the end of the list of free blocks. */
+    xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;
+    xEnd.pxNextFreeBlock = NULL;
+
+    /* To start with there is a single free block that is sized to take up the
+     * entire heap space. */
+    pxFirstFreeBlock = ( void * ) pucAlignedHeap;
+    pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;
+    pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
+}
+/*-----------------------------------------------------------*/

+ 78 - 0
FreeRTOS/portable/MemMang/heap_3.c

@@ -0,0 +1,78 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+
+/*
+ * Implementation of pvPortMalloc() and vPortFree() that relies on the
+ * compilers own malloc() and free() implementations.
+ *
+ * This file can only be used if the linker is configured to to generate
+ * a heap memory area.
+ *
+ * See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the
+ * memory management pages of https://www.FreeRTOS.org for more information.
+ */
+
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
+    #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
+#endif
+
+/*-----------------------------------------------------------*/
+
+void * pvPortMalloc( size_t xWantedSize )
+{
+    void * pvReturn;
+
+    pvReturn = RT_KERNEL_MALLOC( xWantedSize );
+
+    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
+        {
+            if( pvReturn == NULL )
+            {
+                extern void vApplicationMallocFailedHook( void );
+                vApplicationMallocFailedHook();
+            }
+        }
+    #endif
+
+    return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void * pv )
+{
+    if( pv )
+    {
+        RT_KERNEL_FREE( pv );
+    }
+}

+ 447 - 0
FreeRTOS/portable/MemMang/heap_4.c

@@ -0,0 +1,447 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/*
+ * A sample implementation of pvPortMalloc() and vPortFree() that combines
+ * (coalescences) adjacent memory blocks as they are freed, and in so doing
+ * limits memory fragmentation.
+ *
+ * See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
+ * memory management pages of https://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
+    #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 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 )
+
+/* Allocate the memory for the heap. */
+#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
+
+/* The application writer has already defined the array used for the RTOS
+* 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 ];
+#endif /* configAPPLICATION_ALLOCATED_HEAP */
+
+/* Define the linked list structure.  This is used to link free blocks in order
+ * of their memory address. */
+typedef struct A_BLOCK_LINK
+{
+    struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
+    size_t xBlockSize;                     /*<< The size of the free block. */
+} BlockLink_t;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Inserts a block of memory that is being freed into the correct position in
+ * the list of free memory blocks.  The block being freed will be merged with
+ * the block in front it and/or the block behind it if the memory blocks are
+ * adjacent to each other.
+ */
+static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert );
+
+/*
+ * Called automatically to setup the required heap structures the first time
+ * pvPortMalloc() is called.
+ */
+static void prvHeapInit( void );
+
+/*-----------------------------------------------------------*/
+
+/* The size of the structure placed at the beginning of each allocated memory
+ * block must by correctly byte aligned. */
+static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
+
+/* Create a couple of list links to mark the start and end of the list. */
+static BlockLink_t xStart, * pxEnd = NULL;
+
+/* Keeps track of the number of calls to allocate and free memory as well as the
+ * number of free bytes remaining, but says nothing about fragmentation. */
+static size_t xFreeBytesRemaining = 0U;
+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 )
+{
+    BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
+    void * pvReturn = NULL;
+
+    vTaskSuspendAll();
+    {
+        /* If this is the first call to malloc then the heap will require
+         * initialisation to setup the list of free blocks. */
+        if( pxEnd == NULL )
+        {
+            prvHeapInit();
+        }
+
+        /* 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( ( xWantedSize & xBlockAllocatedBit ) == 0 )
+        {
+            /* 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 + xHeapStructSize ) >  xWantedSize ) ) /* Overflow check */
+            {
+                xWantedSize += xHeapStructSize;
+
+                /* Ensure that blocks are always aligned. */
+                if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
+                {
+                    /* 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;
+            }
+
+            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
+            {
+                /* Traverse the list from the start (lowest address) 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 the end marker was reached then a block of adequate size
+                 * was not found. */
+                if( pxBlock != pxEnd )
+                {
+                    /* Return the memory space pointed to - jumping over the
+                     * BlockLink_t structure at its start. */
+                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
+
+                    /* 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 );
+                        configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
+
+                        /* 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;
+
+                    if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
+                    {
+                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
+                    }
+
+                    /* The block is being returned - it is allocated and owned
+                     * by the application and has no "next" block. */
+                    pxBlock->xBlockSize |= xBlockAllocatedBit;
+                    pxBlock->pxNextFreeBlock = NULL;
+                    xNumberOfSuccessfulAllocations++;
+                }
+            }
+        }
+
+    }
+    ( void ) xTaskResumeAll();
+
+    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
+        {
+            if( pvReturn == NULL )
+            {
+                extern void vApplicationMallocFailedHook( void );
+                vApplicationMallocFailedHook();
+            }
+        }
+    #endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
+
+    configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
+    return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void * pv )
+{
+    uint8_t * puc = ( uint8_t * ) pv;
+    BlockLink_t * pxLink;
+
+    if( pv != NULL )
+    {
+        /* The memory being freed will have an BlockLink_t structure immediately
+         * before it. */
+        puc -= xHeapStructSize;
+
+        /* 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( pxLink->pxNextFreeBlock == NULL );
+
+        if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
+        {
+            if( pxLink->pxNextFreeBlock == NULL )
+            {
+                /* The block is being returned to the heap - it is no longer
+                 * allocated. */
+                pxLink->xBlockSize &= ~xBlockAllocatedBit;
+
+                vTaskSuspendAll();
+                {
+                    /* Add this block to the list of free blocks. */
+                    xFreeBytesRemaining += pxLink->xBlockSize;
+                    prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
+                    xNumberOfSuccessfulFrees++;
+                }
+                ( void ) xTaskResumeAll();
+            }
+        }
+    }
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetFreeHeapSize( void )
+{
+    return xFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetMinimumEverFreeHeapSize( void )
+{
+    return xMinimumEverFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+void vPortInitialiseBlocks( void )
+{
+    /* This just exists to keep the linker quiet. */
+}
+/*-----------------------------------------------------------*/
+
+static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
+{
+    BlockLink_t * pxFirstFreeBlock;
+    uint8_t * pucAlignedHeap;
+    size_t uxAddress;
+    size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
+
+    /* Ensure the heap starts on a correctly aligned boundary. */
+    uxAddress = ( size_t ) ucHeap;
+
+    if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
+    {
+        uxAddress += ( portBYTE_ALIGNMENT - 1 );
+        uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
+        xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
+    }
+
+    pucAlignedHeap = ( uint8_t * ) uxAddress;
+
+    /* xStart is used to hold a pointer to the first item in the list of free
+     * blocks.  The void cast is used to prevent compiler warnings. */
+    xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
+    xStart.xBlockSize = ( size_t ) 0;
+
+    /* pxEnd is used to mark the end of the list of free blocks and is inserted
+     * at the end of the heap space. */
+    uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
+    uxAddress -= xHeapStructSize;
+    uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
+    pxEnd = ( void * ) uxAddress;
+    pxEnd->xBlockSize = 0;
+    pxEnd->pxNextFreeBlock = NULL;
+
+    /* To start with there is a single free block that is sized to take up the
+     * entire heap space, minus the space taken by pxEnd. */
+    pxFirstFreeBlock = ( void * ) pucAlignedHeap;
+    pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
+    pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
+
+    /* 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 );
+}
+/*-----------------------------------------------------------*/
+
+static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
+{
+    BlockLink_t * pxIterator;
+    uint8_t * puc;
+
+    /* Iterate through the list until a block is found that has a higher address
+     * than the block being inserted. */
+    for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
+    {
+        /* Nothing to do here, just iterate to the right position. */
+    }
+
+    /* Do the block being inserted, and the block it is being inserted after
+     * make a contiguous block of memory? */
+    puc = ( uint8_t * ) pxIterator;
+
+    if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
+    {
+        pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
+        pxBlockToInsert = pxIterator;
+    }
+
+    /* Do the block being inserted, and the block it is being inserted before
+     * make a contiguous block of memory? */
+    puc = ( uint8_t * ) pxBlockToInsert;
+
+    if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
+    {
+        if( pxIterator->pxNextFreeBlock != pxEnd )
+        {
+            /* Form one big block from the two blocks. */
+            pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
+            pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
+        }
+        else
+        {
+            pxBlockToInsert->pxNextFreeBlock = pxEnd;
+        }
+    }
+    else
+    {
+        pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
+    }
+
+    /* If the block being inserted plugged a gab, so was merged with the block
+     * before and the block after, then it's pxNextFreeBlock pointer will have
+     * already been set, and should not be set here as that would make it point
+     * to itself. */
+    if( pxIterator != pxBlockToInsert )
+    {
+        pxIterator->pxNextFreeBlock = pxBlockToInsert;
+    }
+}
+/*-----------------------------------------------------------*/
+
+void vPortGetHeapStats( HeapStats_t * pxHeapStats )
+{
+    BlockLink_t * pxBlock;
+    size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
+
+    vTaskSuspendAll();
+    {
+        pxBlock = xStart.pxNextFreeBlock;
+
+        /* pxBlock will be NULL if the heap has not been initialised.  The heap
+         * is initialised automatically when the first allocation is made. */
+        if( pxBlock != NULL )
+        {
+            do
+            {
+                /* Increment the number of blocks and record the largest block seen
+                 * so far. */
+                xBlocks++;
+
+                if( pxBlock->xBlockSize > xMaxSize )
+                {
+                    xMaxSize = pxBlock->xBlockSize;
+                }
+
+                if( pxBlock->xBlockSize < xMinSize )
+                {
+                    xMinSize = pxBlock->xBlockSize;
+                }
+
+                /* Move to the next block in the chain until the last block is
+                 * reached. */
+                pxBlock = pxBlock->pxNextFreeBlock;
+            } while( pxBlock != pxEnd );
+        }
+    }
+    ( void ) xTaskResumeAll();
+
+    pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
+    pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
+    pxHeapStats->xNumberOfFreeBlocks = xBlocks;
+
+    taskENTER_CRITICAL();
+    {
+        pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
+        pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
+        pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
+        pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
+    }
+    taskEXIT_CRITICAL();
+}

+ 506 - 0
FreeRTOS/portable/MemMang/heap_5.c

@@ -0,0 +1,506 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/*
+ * A sample implementation of pvPortMalloc() that allows the heap to be defined
+ * across multiple non-contigous blocks and combines (coalescences) adjacent
+ * memory blocks as they are freed.
+ *
+ * See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative
+ * implementations, and the memory management pages of https://www.FreeRTOS.org
+ * for more information.
+ *
+ * Usage notes:
+ *
+ * vPortDefineHeapRegions() ***must*** be called before pvPortMalloc().
+ * pvPortMalloc() will be called if any task objects (tasks, queues, event
+ * groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be
+ * called before any other objects are defined.
+ *
+ * vPortDefineHeapRegions() takes a single parameter.  The parameter is an array
+ * of HeapRegion_t structures.  HeapRegion_t is defined in portable.h as
+ *
+ * typedef struct HeapRegion
+ * {
+ *  uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap.
+ *  size_t xSizeInBytes;      << Size of the block of memory.
+ * } HeapRegion_t;
+ *
+ * The array is terminated using a NULL zero sized region definition, and the
+ * memory regions defined in the array ***must*** appear in address order from
+ * low address to high address.  So the following is a valid example of how
+ * to use the function.
+ *
+ * HeapRegion_t xHeapRegions[] =
+ * {
+ *  { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000
+ *  { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000
+ *  { NULL, 0 }                << Terminates the array.
+ * };
+ *
+ * vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().
+ *
+ * Note 0x80000000 is the lower address so appears in the array first.
+ *
+ */
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
+    #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 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 )
+
+/* Define the linked list structure.  This is used to link free blocks in order
+ * of their memory address. */
+typedef struct A_BLOCK_LINK
+{
+    struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
+    size_t xBlockSize;                     /*<< The size of the free block. */
+} BlockLink_t;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Inserts a block of memory that is being freed into the correct position in
+ * the list of free memory blocks.  The block being freed will be merged with
+ * the block in front it and/or the block behind it if the memory blocks are
+ * adjacent to each other.
+ */
+static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert );
+
+/*-----------------------------------------------------------*/
+
+/* The size of the structure placed at the beginning of each allocated memory
+ * block must by correctly byte aligned. */
+static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
+
+/* Create a couple of list links to mark the start and end of the list. */
+static BlockLink_t xStart, * pxEnd = NULL;
+
+/* Keeps track of the number of calls to allocate and free memory as well as the
+ * number of free bytes remaining, but says nothing about fragmentation. */
+static size_t xFreeBytesRemaining = 0U;
+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 )
+{
+    BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
+    void * pvReturn = NULL;
+
+    /* The heap must be initialised before the first call to
+     * prvPortMalloc(). */
+    configASSERT( pxEnd );
+
+    vTaskSuspendAll();
+    {
+        /* 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( ( xWantedSize & xBlockAllocatedBit ) == 0 )
+        {
+            /* The wanted size is increased so it can contain a BlockLink_t
+             * structure in addition to the requested amount of bytes. */
+            if( ( xWantedSize > 0 ) &&
+                ( ( xWantedSize + xHeapStructSize ) >  xWantedSize ) ) /* Overflow check */
+            {
+                xWantedSize += xHeapStructSize;
+
+                /* Ensure that blocks are always aligned */
+                if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
+                {
+                    /* Byte alignment required. Check for overflow */
+                    if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) >
+                         xWantedSize )
+                    {
+                        xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
+                    }
+                    else
+                    {
+                        xWantedSize = 0;
+                    }
+                }
+            }
+            else
+            {
+                xWantedSize = 0;
+            }
+
+            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
+            {
+                /* Traverse the list from the start (lowest address) 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 the end marker was reached then a block of adequate size
+                 * was not found. */
+                if( pxBlock != pxEnd )
+                {
+                    /* Return the memory space pointed to - jumping over the
+                     * BlockLink_t structure at its start. */
+                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
+
+                    /* 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;
+
+                    if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
+                    {
+                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
+                    }
+
+                    /* The block is being returned - it is allocated and owned
+                     * by the application and has no "next" block. */
+                    pxBlock->xBlockSize |= xBlockAllocatedBit;
+                    pxBlock->pxNextFreeBlock = NULL;
+                    xNumberOfSuccessfulAllocations++;
+                }
+            }
+        }
+
+    }
+    ( void ) xTaskResumeAll();
+
+    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
+        {
+            if( pvReturn == NULL )
+            {
+                extern void vApplicationMallocFailedHook( void );
+                vApplicationMallocFailedHook();
+            }
+        }
+    #endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
+
+    return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void * pv )
+{
+    uint8_t * puc = ( uint8_t * ) pv;
+    BlockLink_t * pxLink;
+
+    if( pv != NULL )
+    {
+        /* The memory being freed will have an BlockLink_t structure immediately
+         * before it. */
+        puc -= xHeapStructSize;
+
+        /* 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( pxLink->pxNextFreeBlock == NULL );
+
+        if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
+        {
+            if( pxLink->pxNextFreeBlock == NULL )
+            {
+                /* The block is being returned to the heap - it is no longer
+                 * allocated. */
+                pxLink->xBlockSize &= ~xBlockAllocatedBit;
+
+                vTaskSuspendAll();
+                {
+                    /* Add this block to the list of free blocks. */
+                    xFreeBytesRemaining += pxLink->xBlockSize;
+                    prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
+                    xNumberOfSuccessfulFrees++;
+                }
+                ( void ) xTaskResumeAll();
+            }
+        }
+    }
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetFreeHeapSize( void )
+{
+    return xFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+size_t xPortGetMinimumEverFreeHeapSize( void )
+{
+    return xMinimumEverFreeBytesRemaining;
+}
+/*-----------------------------------------------------------*/
+
+static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert )
+{
+    BlockLink_t * pxIterator;
+    uint8_t * puc;
+
+    /* Iterate through the list until a block is found that has a higher address
+     * than the block being inserted. */
+    for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
+    {
+        /* Nothing to do here, just iterate to the right position. */
+    }
+
+    /* Do the block being inserted, and the block it is being inserted after
+     * make a contiguous block of memory? */
+    puc = ( uint8_t * ) pxIterator;
+
+    if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
+    {
+        pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
+        pxBlockToInsert = pxIterator;
+    }
+
+    /* Do the block being inserted, and the block it is being inserted before
+     * make a contiguous block of memory? */
+    puc = ( uint8_t * ) pxBlockToInsert;
+
+    if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
+    {
+        if( pxIterator->pxNextFreeBlock != pxEnd )
+        {
+            /* Form one big block from the two blocks. */
+            pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
+            pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
+        }
+        else
+        {
+            pxBlockToInsert->pxNextFreeBlock = pxEnd;
+        }
+    }
+    else
+    {
+        pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
+    }
+
+    /* If the block being inserted plugged a gab, so was merged with the block
+     * before and the block after, then it's pxNextFreeBlock pointer will have
+     * already been set, and should not be set here as that would make it point
+     * to itself. */
+    if( pxIterator != pxBlockToInsert )
+    {
+        pxIterator->pxNextFreeBlock = pxBlockToInsert;
+    }
+}
+/*-----------------------------------------------------------*/
+
+void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
+{
+    BlockLink_t * pxFirstFreeBlockInRegion = NULL, * pxPreviousFreeBlock;
+    size_t xAlignedHeap;
+    size_t xTotalRegionSize, xTotalHeapSize = 0;
+    BaseType_t xDefinedRegions = 0;
+    size_t xAddress;
+    const HeapRegion_t * pxHeapRegion;
+
+    /* Can only call once! */
+    configASSERT( pxEnd == NULL );
+
+    pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
+
+    while( pxHeapRegion->xSizeInBytes > 0 )
+    {
+        xTotalRegionSize = pxHeapRegion->xSizeInBytes;
+
+        /* Ensure the heap region starts on a correctly aligned boundary. */
+        xAddress = ( size_t ) pxHeapRegion->pucStartAddress;
+
+        if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
+        {
+            xAddress += ( portBYTE_ALIGNMENT - 1 );
+            xAddress &= ~portBYTE_ALIGNMENT_MASK;
+
+            /* Adjust the size for the bytes lost to alignment. */
+            xTotalRegionSize -= xAddress - ( size_t ) pxHeapRegion->pucStartAddress;
+        }
+
+        xAlignedHeap = xAddress;
+
+        /* Set xStart if it has not already been set. */
+        if( xDefinedRegions == 0 )
+        {
+            /* xStart is used to hold a pointer to the first item in the list of
+             *  free blocks.  The void cast is used to prevent compiler warnings. */
+            xStart.pxNextFreeBlock = ( BlockLink_t * ) xAlignedHeap;
+            xStart.xBlockSize = ( size_t ) 0;
+        }
+        else
+        {
+            /* Should only get here if one region has already been added to the
+             * heap. */
+            configASSERT( pxEnd != NULL );
+
+            /* Check blocks are passed in with increasing start addresses. */
+            configASSERT( xAddress > ( size_t ) pxEnd );
+        }
+
+        /* Remember the location of the end marker in the previous region, if
+         * any. */
+        pxPreviousFreeBlock = pxEnd;
+
+        /* pxEnd is used to mark the end of the list of free blocks and is
+         * inserted at the end of the region space. */
+        xAddress = xAlignedHeap + xTotalRegionSize;
+        xAddress -= xHeapStructSize;
+        xAddress &= ~portBYTE_ALIGNMENT_MASK;
+        pxEnd = ( BlockLink_t * ) xAddress;
+        pxEnd->xBlockSize = 0;
+        pxEnd->pxNextFreeBlock = NULL;
+
+        /* To start with there is a single free block in this region that is
+         * sized to take up the entire heap region minus the space taken by the
+         * free block structure. */
+        pxFirstFreeBlockInRegion = ( BlockLink_t * ) xAlignedHeap;
+        pxFirstFreeBlockInRegion->xBlockSize = xAddress - ( size_t ) pxFirstFreeBlockInRegion;
+        pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd;
+
+        /* If this is not the first region that makes up the entire heap space
+         * then link the previous region to this region. */
+        if( pxPreviousFreeBlock != NULL )
+        {
+            pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion;
+        }
+
+        xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;
+
+        /* Move onto the next HeapRegion_t structure. */
+        xDefinedRegions++;
+        pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
+    }
+
+    xMinimumEverFreeBytesRemaining = xTotalHeapSize;
+    xFreeBytesRemaining = xTotalHeapSize;
+
+    /* 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 );
+}
+/*-----------------------------------------------------------*/
+
+void vPortGetHeapStats( HeapStats_t * pxHeapStats )
+{
+    BlockLink_t * pxBlock;
+    size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
+
+    vTaskSuspendAll();
+    {
+        pxBlock = xStart.pxNextFreeBlock;
+
+        /* pxBlock will be NULL if the heap has not been initialised.  The heap
+         * is initialised automatically when the first allocation is made. */
+        if( pxBlock != NULL )
+        {
+            do
+            {
+                /* Increment the number of blocks and record the largest block seen
+                 * so far. */
+                xBlocks++;
+
+                if( pxBlock->xBlockSize > xMaxSize )
+                {
+                    xMaxSize = pxBlock->xBlockSize;
+                }
+
+                /* Heap five will have a zero sized block at the end of each
+                 * each region - the block is only used to link to the next
+                 * heap region so it not a real block. */
+                if( pxBlock->xBlockSize != 0 )
+                {
+                    if( pxBlock->xBlockSize < xMinSize )
+                    {
+                        xMinSize = pxBlock->xBlockSize;
+                    }
+                }
+
+                /* Move to the next block in the chain until the last block is
+                 * reached. */
+                pxBlock = pxBlock->pxNextFreeBlock;
+            } while( pxBlock != pxEnd );
+        }
+    }
+    ( void ) xTaskResumeAll();
+
+    pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
+    pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
+    pxHeapStats->xNumberOfFreeBlocks = xBlocks;
+
+    taskENTER_CRITICAL();
+    {
+        pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
+        pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
+        pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
+        pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
+    }
+    taskEXIT_CRITICAL();
+}

+ 12 - 0
FreeRTOS/portable/rt-thread/port.c

@@ -1,5 +1,17 @@
 #include <FreeRTOS.h>
 
+static rt_base_t level = 0;
+
+void vPortEnterCritical( void )
+{
+    level = rt_hw_interrupt_disable();
+}
+
+void vPortExitCritical( void )
+{
+    rt_hw_interrupt_enable(level);
+}
+
 BaseType_t rt_err_to_freertos(rt_err_t rt_err)
 {
     switch(-rt_err)

+ 17 - 0
FreeRTOS/portable/rt-thread/portmacro.h

@@ -59,6 +59,23 @@
     typedef rt_tick_t        TickType_t;
     #define portMAX_DELAY    ( TickType_t ) RT_TICK_MAX
 
+/*-----------------------------------------------------------*/
+
+/* Architecture specifics. */
+    #define portBYTE_ALIGNMENT      RT_ALIGN_SIZE
+    #define portPOINTER_SIZE_TYPE   rt_size_t
+/*-----------------------------------------------------------*/
+
+/* Critical section management. */
+    extern void vPortEnterCritical( void );
+    extern void vPortExitCritical( void );
+    #define portSET_INTERRUPT_MASK_FROM_ISR()         rt_hw_interrupt_disable()
+    #define portCLEAR_INTERRUPT_MASK_FROM_ISR( x )    rt_hw_interrupt_enable( x )
+    #define portDISABLE_INTERRUPTS()                  vPortEnterCritical()
+    #define portENABLE_INTERRUPTS()                   vPortExitCritical()
+    #define portENTER_CRITICAL()                      vPortEnterCritical()
+    #define portEXIT_CRITICAL()                       vPortExitCritical()
+
 /*-----------------------------------------------------------*/
 
     #ifdef __cplusplus

+ 48 - 0
FreeRTOS/task.c

@@ -0,0 +1,48 @@
+/*
+ * FreeRTOS Kernel V10.4.6
+ * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
+ *
+ */
+
+/* Standard includes. */
+#include <stdlib.h>
+#include <string.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+void vTaskSuspendAll( void )
+{
+    rt_enter_critical();
+}
+/*----------------------------------------------------------*/
+
+BaseType_t xTaskResumeAll( void )
+{
+    rt_exit_critical();
+    return pdFALSE;
+}
+/*-----------------------------------------------------------*/

+ 53 - 0
test/test_heap.c

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-24     yangjie      the first version
+ * 2020-10-17     Meco Man     translate to English comment
+ */
+
+/*
+ * Demo: mutex
+ *
+ * This demo demonstrates allocating memory from the heap
+ *
+ */
+
+#include <rtthread.h>
+#include <FreeRTOS.h>
+
+// Set to 1 if using heap_5.c
+#define USE_HEAP_5     0
+
+#if USE_HEAP_5 == 1
+rt_uint8_t heap[512];
+HeapRegion_t heap_regions[] =
+{
+    {heap, 512},
+    {NULL, 0}
+};
+#endif
+
+int heap_sample(void)
+{
+#if USE_HEAP_5 == 1
+    vPortDefineHeapRegions(heap_regions);
+#endif
+    rt_uint8_t *ptr = pvPortMalloc(128);
+    if (ptr == RT_NULL)
+    {
+        rt_kprintf("Memory allocation failed.\n");
+        return -1;
+    }
+    for (rt_uint8_t i = 0; i < 128; i++)
+    {
+        ptr[i] = i;
+    }
+    vPortFree(ptr);
+    return 0;
+}
+
+MSH_CMD_EXPORT(heap_sample, heap sample);