Skip to content

[BUG] vTaskPrioritySet doesn't set event item value according to the inherited priority #1364

@wirelinker

Description

@wirelinker

Describe the bug
I found the code in vTaskPrioritySet() handles inheritance of priority when a task is holding a mutex. But the corresponding event item value is set according to the new priority directly.

FreeRTOS-Kernel/tasks.c

Lines 2936 to 2939 in d33d04b

if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == ( ( TickType_t ) 0U ) )
{
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) );
}

In xTaskPriorityInherit() and vTaskPriorityDisinheritAfterTimeout(), the event item value will be set and reset according to the inheritance condition.

If the code use pxTCB->uxPriority to set event item value, it would be correct.

listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ) ); 

Incorrect event item value may cause something like deadlock when a task trying to take multiple mutexes or semaphores as shown in the below test case.

Target

  • Development board: Pico W
  • Instruction Set Architecture: ARMv6M
  • Toolchain and version: Pico SDK 2.2.0

Host

  • Host OS: Ubuntu 24.04

To Reproduce

Test Case

Step1. Task1 take mutex1.
Step2. Task3 and task4 try take mutex2 at the same time.
Step3. Task1 inherit task2 priority.
Step4. Task1 set it's own priority =2.
Step5. Task1 take mutex2 and block indefinitely.
Result would be:
Task1 will never be unblocked since the event value is higher then task3 and task4, although task1 has higher priority.

Some snippets from console:

///// task2 try to take mutex1
task2 take mutex1] try
task3 take mutex[1] failed
task3 gave mutex[2]
task4 take mutex[2] success
task4 take mutex[1] try
task3 on core 1, pri=3, base_pri=3, evt_val=29, ct=2
task3 take mutex[2] try
///// task1 inherited priority from task2
task1 on core 0, pri=4, base_pri=1, evt_val=28, ct=1
task4 take mutex[1] failed
task4 gave mutex[2]
task3 take mutex[2] success
task4 on core 1, pri=3, base_pri=3, evt_val=29, ct=2
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.
task4 take mutex[2] try
task3 take mutex[1] try
///// 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
/////  task1 try to take mutex2
task1 try to take mutex[2] and block indefinitely.
///// task3 and task4 take mutex2 then mutex1 repeatedly
task3 take mutex[1] failed
task3 gave mutex[2]
task4 take mutex[2] success
task3 on core 0, pri=3, base_pri=3, evt_val=29, ct=3
task3 take mutex[2] try
task4 take mutex[1] try
task4 take mutex[1] failed
task4 gave mutex[2]
task3 take mutex[2] success
task3 take mutex[1] try
task4 on core 1, pri=3, base_pri=3, evt_val=29, ct=3
task4 take mutex[2] try
task3 take mutex[1] failed
task3 gave mutex[2]
task4 take mutex[2] success

Expected behavior
The event item value should be set according to the inherited priority of the task.
And the event item of the task would be inserted in waiting list in a correct order when taking a mutex or semaphore.

Additional context
Test code:
FreeRTOS_kernel_test_for_RP2040 at branch vTaskPrioritySet_event_item_value_de

I also checked the unit test for vTaskPrioritySet(). It could be possible to add check for event item value for current test cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions