Multiple daemon timer tasks


A while back I was tasked with debugging a projtect that used FreeRTOS and the previous developer had used the software timers ALOT. At first glance the system seemd fine and it took me a while to reproduce the aledged bugs that but when i scaled up the workload for the system I reproduced it. In essance; it boiled down to waiting on “things” (queues, semaphores etc.) in timer callback functions that were set by other callback functions. Obviously that caused a lockup. There were no RAM shortage of any kind, so I just reworked the project into separate tasks.
I was however tempted to try another approach, and thats where this thread comes in.

It would have worked if I had had two daemon timer tasks and the ability to choose which daemon each timer should be run on.

Just food for thought: What if FreeeRTOS had support for multiple timer task queues.


Hmm … I can’t see the fundamental benefit of having multiple timer tasks.
The root cause problem you identified was the wrong usage of timers i.e. blocking calls in timer callbacks. This breaks all multiplexed timer implementations except having multiple but limited independent timer instances.
So really solving the original problem would imply a (timer) task per timer which is an overkill for all applications following the recommendations regarding timers resp. using them correctly.

To quote the documentation for timers at

Important information on writing timer callback functions

Timer callback functions execute in the context of the timer service task. It is therefore essential that timer callback functions never attempt to block. For example, a timer callback function must not call vTaskDelay(), vTaskDelayUntil(), or specify a non zero block time when accessing a queue or a semaphore.

At one time (I’m not sure if it is still there) there were conditions where a timer callback blocking could trigger an assert. Basically, the previous developer broke the rule it caused the expected problems.

Generally, anything that needs to wait for something should be a task (or a piece of a task).

The main benefit would have been to be able to have different priorities for the callbacks. But as richard-damon says by quouting the documentation: It is a bad idea to block or delay the timer daemon task.

It would not be a bad idea to have asserts on blocktime to only be 0 for idletask and timer daemon task. I would have been very helpful for me in this particular project as I initially had no idea that the code was executed in a timer callback when i was expecting normal dedicated task context.

// Martin

The one big issue on having an assert on block time != 0 in the timer would be that the timer task itself does block, so any assert would need to have a communication back channel from the timer task to the rest of the system. Thus, it likely would need to be something explicitly requested, and not just enable by defining configASSERT, but yes, it could be useful. I would also think you would want it to be on block time != 0, and not just on actually blocking to avoid race conditions possibly passing.

As far as different priorities of callbacks, my impression has always been that the timer/service task is supposed to be one of (if not the) highest priority tasks, as one of its purposes is to handle requests pended from an ISR, and that includes setting events group bits from an ISR. That implies that timer callbacks should be short and quick, so distinct priorities aren’t that vital. The implication seems to be that a low and slow callback would actually be a a short fast callback that signals a task to do the slow job.

I have at times setup a related task manager at idle priority to enable doing slow low priority operations on a periodic basis.

Besides the secondary role of the FreeRTOS timer task doing certain deferred ISR processing at a high priority I think that timers in general don’t really have priorities because their basic purpose is to signal points in time. This in turn should happen preferably immediately on expiration.
I’ve learned that timers doing (much) more than just signaling time events to (prioritized) worker tasks tend to be a misconception and/or could cause unwanted side effects.
Although it sometimes seems tempting to do so…