I am looking for guidelines that would make it harder for me to write bugs similar to the one I recently discovered in my own code.
Here is the mistake I made:
- serial receiving character on ISR I, storing chars in a buffer. When the received char is EOL, notify a receiving task R, with eIncrement.
- serial receiving task R waits, then when notified clears the notifiedValue, handles the n number of frames in the buffer.
- handling these received frames may imply running long functions. These functions have waits and notifies. I had one of these functions F do that:
- register itself for future notifications from task T, passing xTaskGetCurrentTaskHandle()
- start task T
- when task T is done, it notifies F back (setting bits in the notifiedValue, since there are actually multiple instances of task T)
The issue is that function F runs in the context of task R, so when it registers itself for future notifications from T, it exposes the notifiedValue of R. This means that F waking up may overwrite a value changed by ISR I, and ISR I might increment the notifiedValue while F is waiting… I need to keep the notifiedValues separated.
I see the problem, but I don’t really know how to setup rules for myself to prevent this in the future. I have some ideas:
- don’t run long sub-functions in the context of a task.
- send notifications instead, or start new tasks. This means that these other tasks need a mechanism to notify back when done, which is quickly going to grow old and verbose.
- have a naming convention for functions that may be using waits/notifies, to make it clearer that there is danger.
- keep somehow track of the next available notification index for the current task, so that the subfunction can register itself with a notification index and wait for only that index, and the task T does not overwrite the notified value of task R.
This last one would seem the mos robust and flexible to me, and frankly it wouldn’t surprise me if there was infrastructure for that already. I looked at the definition of tskTCB
, but found only ulNotifiedValue[]
and ucNotifyState[]
. How about a mechanism to “reserve” a given notification index, and to “fetch” the next available one?
How would you do it?