Stream buffer and task notification side effects

Assuming you are using the default sbSEND_COMPLETE, etc. macros in your configuration, am I wrong in my assumption that if a task is actively using the task notification feature directly, and using stream/message buffers either directly or indirectly as part of some API then the task will block waiting for a task notification that was “consumed” by the polling loop inside the stream buffer call?

Now the sbSEND_COMPLETE macros seem to acknowledge this flaw without actually describing in detail why they exist. These macros are a bit messy compared to the rest of the tightly nit kernel if this is indeed why they exist.

If this is indeed the case, would it not make sense to remember any external task notifications within the stream buffer implementation, and restore them before exiting so that the user(or someone constructing a peripheral driver using stream buffers) does not have to warn its users about these side effects?

To elaborate, the sbSEND_COMPLETE and related macros should be made permanent, additionally the stream buffer should have an additional state that is only set when a task notification is received from outside of the stream buffer API, and the sbXXXX_COMPLETE macros can have the calling task send a task notification to itself, without changing the value(current code looks like it preserves this value intentionally which is odd given it does not preserve the notification status).

I am currently using the above method in most of the peripheral drivers I have designed to implement a low memory(stack may negate this, not sure) semaphore that does not care whether or not the calling task utilizes the notification feature.

I may be wrong in my assumptions, but the existence of the above mentioned macros makes me think otherwise.

I am sure my explanation is a bit confusing so feel free to ask questions so I can elaborate.

In summary, if task notifications are being used by a task that is also using stream buffers, any task notifications received other than send or receive complete notifications will be lost. This is somewhat addressed by the sbXXXX_COMPLETE macros but this critical flaw(unless I am misunderstanding) is not clear at all.

If someone is relying on an event sent by a task notification, and it is infrequent, or happens to always occur while that same task is communicating using a stream buffer, that event will only ever be handled the next time the notification state is set, if it ever is.

EDIT: Another thing my peripheral drivers do to avoid losing “external task notifications” is they will also set the “restore notification state” variable if they attempt to send a task notification but see that an external event has already set it. This external event will of course serve the purpose of waking up the task to handle the peripheral driver event, but right before exiting the driver will send itself a task notification so the caller will immediately handle its own event.

No, not wrong.

Do you mean why the macro exists? Primarily for core to core communication scenarios:

We have some proof of concept code that uses arrays of task notifications so different scenarios can use different notifications. Not sure when this will be upstreamed yet.

I am wrong about the macro documentation not being explicit! It has been a while since I was initially dealing with this issue.

This would mean that the use cases for stream buffers are limited to those where you know how those macros are defined?

Awesome, I honestly just wanted to know if this issue has been noticed since parts of my current code are written a lot like stream buffers except with the notification state preserved.

Might I suggest that instead of using arrays, you dissociate the task notifications from the task all together and have the state stored independent from the TCB? I guess this might be far from their intended use case, but it would allow for what would appear(from my limited knowledge)to be a alternative to binary semaphores(when used within another library/API) when you only have one task blocked at any time. This is already possible with your current API, I can confirm, but definitely has unnecessary overhead, and may even outweigh a semaphore despite my best intentions.

Anyways it is great to hear you are working on something similar!

Thank you for the very fast reply!