Hello, I was reading the code of vTaskPrioritySet() in tasks.c.
And I found the API just set value of xEventListItem depends on uxNewPriority directly.
If the target task didn’t use inherited uxPriority, then that would be fine. Because uxBasePriority == uxPriority == uxNewPriority at the time of setting.
But if the target task was using inherited uxPriority, we would get different results.
uxNewPriority == uxPriority > uxBasePriorityuxPriorityno changeuxBasePriority = uxNewPriority
uxNewPriority > uxPriority > uxBasePriorityuxPriority = uxNewPriorityuxBasePriority = uxNewPriority
(uxNewPriority < uxPriority) && (uxNewPriority != uxBasePriority)uxPriorityno changeuxBasePriority = uxNewPriority
And the value of xEventListItem will be set to (configMAX_PRIORITIES - uxNewPriority) without regard to the uxPriority.
Then we could get some fun results:
ex.
uxPriority = 20;
uxBasePriority = 2;
uxNewPriority = 1;
xEventListItemValue = (configMAX_PRIORITIES - uxNewPriority) = 32 - 1 = 31;
uxPriority + xEventListItemValue = 20 + 31 = 51;
With a not matched event item value, a high priority task would be put in an incorrect location in an event list when going to block on a kernel object. Then another lower priority tasks will always sit before the high priority task. And the high priority task will never get unblocked. That could be not easy to debug, since we used to check priority of a task instead of event item value. (We can get uxPriority and uxBasePriority by API now. There has no API to get event item value so far. It may be a good idea to add an API for it. But event item value only be used in kernel basically.)
I then checked xTaskPriorityInherit() and vTaskPriorityDisinheritAfterTimeout(). These two APIs are used in mutex mechanism. And they handle event item value depends on inherited uxPriority.
I also did some test on RP2040 to verify the behavior of vTaskPrioritySet() : vTaskPrioritySet_event_item_value .
pre-condition:
task1 priority = 1;
task2 priority = 4;
task1 hold mutex1;
Some simplified console output:
///// task2 try to take mutex1
task2 take mutex1] try
///// task1 inherited priority from task2
task1 on core 0, pri=4, base_pri=1, evt_val=28, ct=1
task1 on core 0, pri=4, base_pri=1, evt_val=28, ct=2
///// set task1 it's own priority = 2
task1 set priority = 2.
///// task1 priority = 4, event value = 30, 4 + 30 = 34 > 32 == configMAX_PRIORITIES
task1 on core 1, pri=4, base_pri=2, evt_val=30, ct=3
I tried to search topics in forum as well:
- An old topic about adding behavior to set event item value.
- An topic talking about why not to reinsert an event item after set priority dynamically.
- That would be an non-deterministic activity. Since unknown number of tasks could block on the same kernel object (ex. an event_group). The event item list would have unknown length. So the reinsertion may cost unknown time.
- What I thought is:
- Even though we are not going to reinsert event item. The value still matters to the tasks which are going to block itself.
- A 2023 post, which opened a PR: Use the bigger priority whenever possible.
- The commit
60ef67cadded dynamic priority change when a task is using an inherited uxPriority. - The code before this commit also changes event item value without regard to uxPriority.
That’s what I’ve done so far.
Thanks.