Clarifying some FreeRTOS terminology

Hello,

Apologies if this is an elementary topic, but I am a bit confused as to the terms and the meanings used in a typical C program vs those used in a FreeRTOS context, and would like to clear them up. My setup is a Zybo Z7 board running FreeRTOS v10.0. I am using the heap_4.c file.

  1. I understand that in a baremetal C program, the heap size specified in the linker script sets the upper bound of memory that can be allocated dynamically (during run time) by malloc(). The stack segment is used to hold function arguments and local variables during function calls, also during run time.

  2. As per this thread (https://support.xilinx.com/s/question/0D52E00006hpUz3SAE/freertos-and-heap-and-memory-management?language=en_US), when using FreeRTOS with the heap_4.c scheme, the memory required for all tasks and kernel objects are statically allocated – ie, they live in the global segment of the memory (.bss) . Moreover, calls to pvPortMalloc() allocate memory from this already pre-allocated memory, so no memory from the heap segment is used. The max static memory allocated is controlled by the configTOTAL_HEAP_SIZE setting. The following experiment seems to confirm this being the case :

Heap size in linker.ld =0 + configTOTAL_HEAP_SIZE set to 64 
   text	   data	    bss	    dec	    hex	filename
  88796	   4168	   8576	 101540	  18ca4	test_malloc_pvPortMalloc.elf

Heap size in linker.ld =0 + configTOTAL_HEAP_SIZE set to 512
   text	   data	    bss	    dec	    hex	filename
  88796	   4168	   9024	 101988	  18e64	test_malloc_pvPortMalloc.elf

The following line in heap_4.c also confirms that this is the case :
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];

  1. Following on from 2., this means we can technically allocate a heap of 0B in the linker script and then use pvPortMalloc() to allocate some memory and we should get a non-NULL pointer value to this memory.

  2. From this thread (Heap clarification - FreeRTOS), the space for all task stack and kernel objects is statically allocated from the statically declared memory bound by configTOTAL_HEAP_SIZE. Does the task stack include space for local variables in function calls during calls? If so, then the actual ‘stack’ as in C parlance, doesn’t get used when running FreeRTOS. Is this a correct interpretation?

  3. From (Effect of stack size and heap size value in the linker script (Xilinx Zynq SDK) - FreeRTOS), it looks like
    a) The stack size in the linker script will be the stack given to the ‘main’ program (what runs pre-scheduler) and will be reused as the interrupt stack when the scheduler starts.
    b) The heap size in the linker script will be the amount of heap available via the standard C malloc function (as opposed to the statically created memory for FreeRTOS tasks, objects and memory allocated via pvPortMalloc() that heap4.c provides)
    Is this interpretation correct?

  4. Given the above, how do we interpret the distinction between ‘static’ and ‘dynamic’ allocation as discussed here (FreeRTOS Static Memory Allocation)? It looks like to me like all memory required for FreeRTOS tasks and objects are statically allocated (since I am using heap_4.c), with the scheme providing functionality of organizing the allocated memory to reduce fragmentation if tasks and/or objects get deleted.
    Is this correct?

Apology for the long post. Thanks for the help!
yogesh

Basically all points are correct and 5. is a correct summary.
Don’t get confused with using a static RAM array as heap memory compared to using a linker specified section as heap memory.
In the end both approaches provide a raw block of memory used by the respective heap implementation which provides the dynamic memory management resp. allocation for the application.
heap_4.c and all others are generic, self containing heap implementations to be used on a lot of MCUs and various compiler / linker toolchains. Hence it’s intentionally independent from any linker script defined symbols etc. Also the usually provided linker scripts might be hard to adopt for many users… :wink:

Thanks for the reply Hartmut. The significant difference between having a static RAM array vs a linked defined heap section would be that the former is placed in the .bss segment and hence somewhat protected by corruption due to overflows of the program stack and heap.

Referring to 6, on further looking, it appears the ‘static vs dynamic allocation’ probably refers to the fact that even though the space for the tasks are allocated statically, ‘static’ here refers to the fact that the memory so allocated initially will not be repurposed during run time, whereas ‘dynamic’ refers to the fact that an initially (statically) allocated block of memory for a task/object may be repurposed during run-time if the task/object were to be deleted. Is this a correct interpretation?

It’s right. That’s the idea of dynamic memory management with all its pros and cons.
You see, static is used with differing meanings depending on the context.
Considering higher level dynamic memory management there is no such thing as statically allocated in the sense you mentioned. It’s not important that the underlying heap management code uses a static array (could be just a global array) or something else but provides an allocate/free user interface. Also you can map/place a static or global variable to a specific other memory section or segment than the default .bss (e.g. __attribute__ ((section ("RAM_BANK2")))) in case you have multiple RAM banks in your system and defined them in the linker script.
The raw block(s) of memory used by a heap implementation is just an implementation detail.

Alright, thanks for the replies Hartmut.