Dynamic vs static allocation of the tasks

A few questions to clarify:

  • xTaskCreate() allocates a stack on the heap for this specific task whereas xTaskCreateStatic allocates a stack in… stack memory?

  • Do you decide to allocate on the heap when you don’t know how much stack size you need at compile time? Even when you’re statically allocating, how do you determine how much memory would your task consume to begin with?

  • If you allocate the task on the heap, you don’t have to worry about deleting it? What happens to the allocated memory?

Did you ever read the docs e.g for xTaskCreate ?
I’d highly recommend to read the docs first. It’ll help you a lot :+1:
Estimating the right stack size is not so easy especially when using unknown 3rd party libraries. However, start with a rather large stack (1-2 kB) having configCHECK_FOR_STACK_OVERFLOW set to 2 along with vApplicationStackOverflowHook implemented and e.g. use usTaskCheckFreeStackSpace to determine, how much is really needed.

I see configCHECK_FOR_STACK_OVERFLOW is mainly used for checking stack overflow but where’s usTaskCheckFreeStackSpace defined? can’t seem to find its definition. How does usTaskCheckFreeStackSpace determine the space needed though? Only the application writer would have some sort of an idea, no?

And I am still unclear about the free’ing of allocated memory part

Generally, the xxxxCreateStatic are given static (often file local global) memory to make the object. The advantage here is that this memory will be accepted for directly by the linker, as opposed to making sure you had enough heap reserved for it. The disadvantage is that if for some reason you decide not to create it, or later destroy it, it will still be occupying the memory. It is a ‘Static’ (un changing) allocation. A task stack so allocated can’t be adjusted at run time to be bigger.

Things created on the heap, can come and go and give up their memory for other uses.

If you don’t need the dynamic nature of a dynamic object (you will create a fixed number of them for the life of the program) than static creation is simplest in my mind, you will know after linking a very good state of your memory consumption. (You do still need to get stack sizes right),

usTaskCheckFreeStackSpace is in Task.c, it check that stack, at that point in time, and sees how much has been used, by looking at the stack pointer, and optionally by scanning the stack space to see what has been written into, to determine the stack usage. Note, it can only find overflows “after the fact”, but often it will find it quick enough to halt the system with the specific error before the system dies due to what was overwritten.

The disadvantage is that if for some reason you decide not to create it, or later destroy it, it will still be occupying the memory

the task is statically allocated meaning it’s allocated in the local scope/stack as opposed to on the heap, isn’t it? (as apparent in this example.
Given that’s the case, what’s the need to “destroy” it? I’m thinking it as something local/auto which gets deleted once the scope goes away.

usTaskCheckFreeStackSpace is in Task.c,

I did look it up but there’s no such occurrence.

Look where the buffers are allocated, OUTSIDE any function, so ‘file scope’, i.e ‘statically allocated’, not as an automatic variable in the task stack. (The HANDLE, which is just a pointer to it, is placed in a stack variable).

As to where the actual stack checking occurs, there is a macro, at least in the version I am using called taskCHECK_FOR_STACK_OVERFLOW() which is defined is stack_macros.h (I think it used to be in tasks.c) that does the actual checking.

I see the handle is of type StaticTask_t but how is it defined as static without the keyword? i’ve been digging through the definitions but couldn’t find it.

Hm, gotcha. So would you call taskCHECK_FOR_STACK_OVERFLOW() to manually check how much stack is being consumed?

I want to add that I used the debugger (manually checking memory dump of the stack space using pxCurrentTCB struct pointer) to check the stack usage. Stack memory is initially filled with 0xA5 pattern with configCHECK_FOR_STACK_OVERFLOW being set.
If I’m not wrong (again) the up-to-date function for stack usage evaluation is uxTaskGetStackHighWaterMark or combined with other information vTaskGetInfo.
Sorry for the confusion.

The lines

 /* Structure that will hold the TCB of the task being created. */
    StaticTask_t xTaskBuffer;

    /* Buffer that the task being created will use as its stack.  Note this is
    an array of StackType_t variables.  The size of StackType_t is dependent on
    the RTOS port. */
    StackType_t xStack[ STACK_SIZE ];

create chance of memory at file scope, which is what we call a ‘static’ allocation. (adding the keyword static would affect the linkage of the, making it local to that file instead of global, and probably should have been done, except it might clutter the example. Neither of these is the task handle, these are INPUTS to the create call to provide the memory, so it doesn’t need to allocate the memory dynamically.

FreeRTOS will call taskCHECK_FOR_STACK_OVERFLOW() when it is swapping a task out, I don’t think you can use that macro, as it needs information from task.c to run. If YOU want to know how much stack is left for a task, you can call uxTaskGetStackHighWaterMark().

maybe the terms are confusing here. doesn’t static allocation refer to allocating variables with static keyword?

I’m using eclipse and I see it has Static Stack Analyzer window which shows the local cost of the variables/functions being used, but doesn’t show the memory left

The ‘Static Stack Analyzer’ is something very different. That is an option where the compiler analyzes your code and figures out how much stack each function uses, then adds the largest amount that any of the function it calls uses (recursing to the end). There are some functions it can’t handle (most those that use recursion). It can give you a good guide about how big to make your stack for a give task.

Note, in C, ‘static allocation’ (in the sense as opposed to dynamic and automatic) isn’t just by the static key word (which is somewhat overloaded in meaning). Global variable, those outside a function without the static keyword are also ‘static’ in allocation. There the keyword static doesn’t affect the type of allocation, but the scope, changing it from global to file.

If you use xTaskCrateStatic() then the application writer decides where the stack is placed in memory - following the normal C language rules. You can make it a global variable, file scope variable, function scope static variable (must be static if at function scope to stop it being allocated on a stack which won’t exist any more if the function exits).

You can check the stack usage using https://www.freertos.org/uxTaskGetStackHighWaterMark.html or https://www.freertos.org/vTaskGetInfo.html or https://www.freertos.org/uxTaskGetSystemState.html or a kernel away IDE plugin.

right, so they’re statically allocated but any reason why they’re global and not static cause they’re passed into the xTastCreate() anyways?

also, regarding manually debugging, do you determine how much stack is being used by subtracting the top (pxTopOfStack) by the base stack address (pxStack I reckon)?

I suspect just so as to not clutter the example.
I would have used static modifier on those (if I was doing it that way).

For machines with downward growing stacks, you can subtract the current stack pointer from the initial stack pointer (if you know it) to get stack used. You can subtract the base of the stack (the address listed in the TCB as pxStack) from the current stack pointer to find how much is left.

Note, the variable pxTopOfStack was the stack pointer when the task was last switched out.
The Top address of the stack is stored in pxEndOfStack if the stack grows up or you define configRECORD_STACK_HIGH_ADDRESS = 1

In addition you can see in the debugger how much stack wasn’t touched by checking the remaining stack memory still filled with the magic 0xA5 pattern or e.g. on ARM CortexM3/4 MCUs by checking difference of pxEndOfStackof the current task and the PSP register which is the current thread mode stack pointer.

Doesn’t pxEndOfStackof refer to the top of the stack at least in case of growing downwards?

pxEndOfStack is the highest address for the stack frame, which for a downward growing stack would be the initial stack pointer before the initial stack frame is created. For a stack, ‘Top’ tend to refer to the active end of the stack, where you put new items on and take them off.

So by address we have

pxStack < pxTopOfStack < pxEndOfStack
lowest _ _ _ <-active->_ _ _ _ _ _ _ highest