FreeRTOS task stack memory saftey, direct task notificaiton

Hi,

I’m reading about the direct task notification, noted the content ulvalue is a 32-bit number. I am wondering, would it be possible to set the value to a pointer to a stack? Hence can pass information of any length.

Consider an example with multiple sender tasks and a receiver task. Each sender knows an index starting from 1. The same index is reserved in the notification array of the receiver, so the receiver can know who send the message.

  1. The sender may send a notification to the receiver at their index, with a context being a pointer to a struct in their stack.
  2. The sender then blocks until the receiver sends an ack back in some form. (i.e. sender will not change stack once the notification is sent).
  3. The sender then resumes, corrupting the original content in the stack.

My question is would this work? Is there any chance the stack of the sender would change/corrupt in step 2? Such as a result of memory defragmentation? If there are issues, what would be the best way to fix them?

As a follow-up question: It seems the notification API can only query one index at a time (via xTaskNotifyWait), is there a way to get a bitmap of all the notification state and without blocking? So I can do a quick binary hack to handle the correct notification and skip there is no notification to handle.

I know I can always use a queue, but I want to make it efficient and elegant.

Thanks,
Ben

That would work, with the safeguard you mention of ensuring the stack remains valid until the receiver tells you its ok for it to unwind. You also have the option of using a stream or message buffer instead of a queue - might be better.

It sounds like it also might just be simpler to set a global pointer variable, and then signal with a single bit notification. That also would allow the receiver to block on a single word and get 32 channels of notifications in.

I was really excited to get such a fast reply. I felt some more contexts would aid the discussion.

  1. The sender tasks are created and deleted dynamically (in-frequent), by a manager task.
  2. The system would be expected to have many (20+) sender tasks running. Really depends on how much RAM is available. (The task are distributed across many nodes, so it’s not a hard constraint. Max 255 sender tasks may exist in the system)
  3. The sender tasks are event-driven, meaning they will be blocked most of the time.
  4. As a result of 2 and 3. I suspect the system to be memory-bound. So I want to conserve RAM whenever possible, that’s why I have the idea of using the stack to save space.
  5. The length of each message is known at compile time. (It would be great if someone can also point me on how to calculate actual stack size statically, assume no recursion call exist)

@rtel I have a brief look at the message buffer and the MessageBufferAMP example. It is quite inspiring, but I felt it would not suit this task given the context above?

@richard-damon This indeed is an option. So having an array of 32 pointers. :thinking:

My “unoptimised/original” thought is to have a single queue, written by all sender and read by the receiver. Each message would include an id/handle of the sender and a pointer to the message on the stack. But was excited by the 45% faster and less RAM that the direct task notification promised.

I’m still deciding between

  • notification like I originally posted
  • notification like @richard-damon proposed
  • message buffer like @rtel mentioned
  • unoptimised queue like I just posted

Any suggestion is really welcome!
ps: I have edited my question to add a follow-up question on how to query pending notification without calling xTaskNotifyWait many times.

Given the context you provided I agree a stream/message buffer is probably not the best option after all.

My first thought is that you need to make sure that creating and destroying all these tasks is the right answer. Unless some of these tasks need a lot more memory than others, so you need to trade off at times fewer tasks with more memory per task vs more tasks with less memory per task as the system is running, it may be better to just allocate a ‘pool’ of tasks and then a task picks up a request and runs. that function.

Since all the tasks can share the same code base, sending a start command to a queue which all idle tasks read from, may give your better performance. The key issue is that when you create and destroy tasks repeatedly, you can start to fragment you heap and effectively drop the amount of memory you have to operate with.

If you get more than 32 wanting to send, then the notification option gets less useful, as you can’t just set a bit. At that point perhaps just a queue with pointers (and maybe and ID if that can’t be in the data) may be better, though it still might be more efficient to use an array of pointers and a short critical section for finding and filling in a pointer.

As to stack size, gcc has a static stack analysis tool in some versions.

Hi there Ben,

we had discussed the issue in a different thread before (here): It may not be a wise idea to create and destroy tasks dynamically. These are expensive procedures that may, among other things, account for memory fragmentation (even if you create the tasks with static stacks driven from a pool, there is still one alloc() made for each PCB creation) and potentially take up significant CPU time. If I recall correctly, task deletion is also a process that is deferred to the idle task, which means that the true release of resources also depends on how heavily your working tasks utilize the CPU which in turn affects real time behavior.

The more traditional solution would be to use a static pool of tasks which sit dormant until being signalled to pick up a computation.

Feel free to experiment with your strategy, and please let us know how that works out, but keep the more traditional approach in the back of your mind as a valid Plan B.

Thanks!