In a project that I’m following I happened to face a problem related to how the priority inheritance is managed in FreeRTOS, or rather how it is dehinerited.
First of all I make a recap of what I understood about priority inheritance management.
Here is Task 1 (green) which normally has low priority, and Task 2 (red) with high priority.
- time t1: is running task 1 that takes mutex M1
- time t2: task 1 takes mutex M2 too
- time t3: task 1 is preempted by task 2
- time t4: task 2 wants to take mutex M2, but it is owned by task 1. This causes task 2 to be blocked (waiting for the M2 mutex to be released), and the priority of task 1 to be raised to that of task 2. Task 1 is now running.
- time t5: task 1 release M2. This should cause its priority to be lowered by allowing task 2 to run and take the M2 mutex in turn. FreeRTOS doesn’t do this, it keeps task 1 priority high.
- time t6: task 1 release M1 (its last mutex owned). This is where FreeRTOS finally lowers the priority of task 1 again. Task 2 can now run and take M2.
- time t7: task 2 release M2.
The time between t5 and t6 is given to task 1 when task 2 should get it. Otherwise is partially thwarted the effect of the priority inheritance on the priority inversion issue. Between t5 and t6 there is no reason why task 1 should have priority equal to task 2, leaving the possibility that task 1 delays further task 2.
After this premise, I would like to discuss how FreeRTOS could be modified to implement the priority inheritance protocol in a more correct way.
I read a couple of books and some online articles to learn more about the problem. All the sources I found agree that the priority must be lowered (but maybe better to say ‘recalculated’) when the mutex that made it rise is released.
So, thinking a little bit, I came to the following conclusion:
Having a function that given a mutex returns the highest priority among the processes blocked on that mutex (if any).
To have a function that given a mutex returns the process that owns it (if owned)
The recalculation of the priority should take place in the following cases:
- A task releases a mutex. Its priority must be recalculated (it is not always the basepriority).
- A task blocked on a mutex expires the timeout. The priority of the task that owns the mutex must be recalculated.
- A task blocked on a mutex is deleted. If the task was blocked on a mutex, the priority of the process that owns it must be recalculated.
- A task blocked on a mutex is forcibly unblocked (using
xTaskAbortDelay()). If the task was blocked on a mutex, the priority of the process that owns it must be recalculated.
I think that’s all, but tell me if I forgot something or made a mistake.
I would be curious to know why on FreeRTOS the priority inheritance has been implemented so and never changed.
If it was a performance problem I think that adding some more fields in the
xQUEUE structures (only in case of mutex i.e.
configUSE_MUTEXES==1) it would be possible to get the feature without excessive computational cost.
could, the set of changes that I have roughly described above, be considered to be included in the main line of FreeRTOS?