Support allocating stack from separate heap (#267)

The change adds support for allocating task stacks from separate heap.
When configSTACK_ALLOCATION_FROM_SEPARATE_HEAP is defined as 1 in
FreeRTOSConfig.h, task stacks are allocated and freed using
pvPortMallocStack and vPortFreeStack functions. This allows the
application writer to provide a separate allocator for task stacks.

When configSTACK_ALLOCATION_FROM_SEPARATE_HEAP is defined as 0, task
stacks are allocated and freed using FreeRTOS heap functions
pvPortMalloc and vPortFree.

For backward compatibility, configSTACK_ALLOCATION_FROM_SEPARATE_HEAP
defaults to 0.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
diff --git a/.github/lexicon.txt b/.github/lexicon.txt
index d2ac65f..9ffef9a 100644
--- a/.github/lexicon.txt
+++ b/.github/lexicon.txt
@@ -1617,6 +1617,7 @@
 pvparameter
 pvparameters
 pvportmalloc
+pvportmallocstack
 pvportrealloc
 pvreg
 pvrxdata
diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h
index df263a1..9573258 100644
--- a/include/FreeRTOS.h
+++ b/include/FreeRTOS.h
@@ -896,6 +896,11 @@
     #define configSUPPORT_DYNAMIC_ALLOCATION    1

 #endif

 

+#ifndef configSTACK_ALLOCATION_FROM_SEPARATE_HEAP

+    /* Defaults to 0 for backward compatibility. */

+    #define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP   0

+#endif

+

 #ifndef configSTACK_DEPTH_TYPE

 

 /* Defaults to uint16_t for backward compatibility, but can be overridden

diff --git a/include/portable.h b/include/portable.h
index 4f4c1d5..f836747 100644
--- a/include/portable.h
+++ b/include/portable.h
@@ -179,6 +179,14 @@
 size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;

 size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;

 

+#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 )

+    void *pvPortMallocStack( size_t xSize ) PRIVILEGED_FUNCTION;

+    void vPortFreeStack( void *pv ) PRIVILEGED_FUNCTION;

+#else

+    #define pvPortMallocStack pvPortMalloc

+    #define vPortFreeStack vPortFree

+#endif

+

 /*

  * Setup the hardware ready for the scheduler to take control.  This generally

  * sets up a tick interrupt and sets timers for the correct tick frequency.

diff --git a/tasks.c b/tasks.c
index fc44c81..6ba21bb 100644
--- a/tasks.c
+++ b/tasks.c
@@ -748,7 +748,7 @@
                     /* Allocate space for the stack used by the task being created.

                      * The base of the stack memory stored in the TCB so the task can

                      * be deleted later if required. */

-                    pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */

+                    pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */

 

                     if( pxNewTCB->pxStack == NULL )

                     {

@@ -763,7 +763,7 @@
                 StackType_t * pxStack;

 

                 /* Allocate space for the stack used by the task being created. */

-                pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */

+                pxStack = pvPortMallocStack( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */

 

                 if( pxStack != NULL )

                 {

@@ -779,7 +779,7 @@
                     {

                         /* The stack cannot be used as the TCB was not created.  Free

                          * it again. */

-                        vPortFree( pxStack );

+                        vPortFreeStack( pxStack );

                     }

                 }

                 else

@@ -3950,7 +3950,7 @@
             {

                 /* The task can only have been allocated dynamically - free both

                  * the stack and TCB. */

-                vPortFree( pxTCB->pxStack );

+                vPortFreeStack( pxTCB->pxStack );

                 vPortFree( pxTCB );

             }

         #elif ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */

@@ -3962,7 +3962,7 @@
                 {

                     /* Both the stack and TCB were allocated dynamically, so both

                      * must be freed. */

-                    vPortFree( pxTCB->pxStack );

+                    vPortFreeStack( pxTCB->pxStack );

                     vPortFree( pxTCB );

                 }

                 else if( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_ONLY )