[smp]question about the function:prvSelectHighestPriorityTask

Function name:

    #if ( configNUMBER_OF_CORES > 1 )
    static void prvSelectHighestPriorityTask( BaseType_t xCoreID )
    #endif

Code snippet:

    if( ( uxCoreMap & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )
    {
        /* The ready task that was removed from this core is not excluded from it.
        * Only look at the intersection of the cores the removed task is allowed to run
        * on with the cores that the new task is excluded from. It is possible that the
        * new task was only placed onto this core because it is excluded from another.
        * Check to see if the previous task could run on one of those cores. */
         uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask );
    }

Question:
why? uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask );
If the system has three tasks and two cores(core0, core1), the following is the detailed:

  1. Task a, priority 8, uxCoreAffinityMask 0xffffffff;
  2. Task b, priority 7, uxCoreAffinityMask 0xffffffff;
  3. Task c, priority 6, uxCoreAffinityMask 0xffffffff;
    The current tcb is task b at the core0, and the current tcb is task c at the core1. At this time, task a preempts the task b of core0, and then core0 shall notify core1 of a scheduling event, because task b will preempts the task c, and run at the core1.

Now let’s follow the code logic to understand it:
the variable uxCoreMap is the previous tcb’s value: task b, uxCoreMap=0xffffffff;
the pxCurrentTCBs[xCoreID] is task b with uxCoreMap=0xffffffff;
at last uxCoreMap is equal to 0. In other words, prvSelectHighestPriorityTask can not invoke the prvYieldCore.

why so? thx

Thank you for your feedback. I will look into the details and discuss with you later.

Hi wangzhilei,

In your example, the task C should be preempted by task A instead of task B since task B has higher priority.

Let’s also consider another situation that task B is preempted by task A due to core affinity.

  • TASK A, priority 8, uxCoreAffnityMask = core0
  • TASK B, priority 7, uxCoreAffnityMask = core0 | core1 ( Running core 0 )
  • TASK C, priority 6, uxCoreAffnityMask = core0 | core1 ( Running core 1 )

In this example, Task B will be preempted by Task A.
In the code snippet above, the initial uxCoreMap is

uxCoreMap = core0 | core1;

After excluding Task A’s core map, Task B is allowed to run on core1 only.

uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask );
=> uxCoreMap = core1

Task B can still preempt Task C.

There may be more situation not been mentioned in the discussion. Please feedback and we would like to discuss with you in this thread.

1 Like

Still a bit confused。

Fresh:“In your example, the task C should be preempted by task A instead of task B since task B has higher priority.”;

Wangzhilei:

  1. Task a, priority 8, uxCoreAffinityMask 0xffffffff;
  2. Task b, priority 7, uxCoreAffinityMask 0xffffffff; (Running core 0)
  3. Task c, priority 6, uxCoreAffinityMask 0xffffffff; (Running core 1)

Assuming it’s a dual-core system,In my opinion, there are two cases:
1), task a is added into ready list at the core 0, and a context switch occurs.
1.1, task b is preempted by task a at the core 0, and then core 0 notifies core 1;
1.2, task c is preempted by task b;
2), task a is added into ready list at the core 1, and a context switch occurs.
2.1, task c is preempted by task a;

The final outcome of the two scenarios is that task a runs on one core, and task b runs on another core.

The description of the previous post might not be clear. Let me explain again following the code

Source code:
FreeRTOS-Kernel/tasks.c at ae3a498e435cecdb25b889f2740ea99027dd0cb1 · FreeRTOS/FreeRTOS-Kernel (github.com)

Function name:

#if ( configNUMBER_OF_CORES > 1 )
    static void prvSelectHighestPriorityTask( BaseType_t xCoreID )
#endif

Precondition
0, Dual-core system;
1, Task b, priority 7, uxCoreAffinityMask 0xffffffff; (Running core 0);
2, Task c, priority 6, uxCoreAffinityMask 0xffffffff; (Running core 1);
3, Task a, priority 8, uxCoreAffinityMask 0xffffffff;
4, A contex switch occur at the core 0, and task a is at the pxReadyTasksList[8];

Code Section line 935–line 1070 [ FreeRTOS-Kernel/tasks.c at ae3a498e435cecdb25b889f2740ea99027dd0cb1 · FreeRTOS/FreeRTOS-Kernel (github.com)]
Search the current highest-priority task from ready lists;
uxTopReadyPriority = 8, uxCurrentPriority = 8
pxPreviousTCB is the handle of task b;
pxCurrentTCBs[ xCoreID ] is the handle of task a;

Code Section line 1072–line 1146
The main task of this code snippet is to determine whether to notify other cores to trigger a context switch. is it right?

Confusing points
0, line 1076, ( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxPreviousTCB->uxPriority ] ), &( pxPreviousTCB->xStateListItem ) ) != pdFALSE )
The pxPreviousTCB is the previous current tcb: task b at the core 0. At the time, this list node must be on the ready list. In other words, the container of pxPreviousTCB->xStateListItem must be pxReadyTasksLists[ pxPreviousTCB->uxPriority ]. Why is there a need to check here?

1, line 1097, uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask );
For the previous task is running at the core 0 right now, the condition expression(if( ( uxCoreMap & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U )) is true. After excuting the c expression (uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask ))
uxCoreMap is equal to 0.
why uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask )?Why is this sentence necessary? It doesn’t seem logical.

Looking forward to your clarification for me. thank you very much

  • Why is there a need to check here? Line 1076
                if( ( pxPreviousTCB != NULL ) && ( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxPreviousTCB->uxPriority ] ), &( pxPreviousTCB->xStateListItem ) ) != pdFALSE ) )
                {

The pxPreviousTCB can be put into another list. For example, the running task just blocked itself by calling vTaskDelay and been put into a delay list. Later yield function is called in vTaskDelay to run other task. In that case, yield other running task for this task for core affinity is not required.

  • why uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask )?

The purpose of the code snippet doesn’t seem to be valid now. Let me bring back the problem for more discussion.

I would like to describe more about the example you provided. When a task is put into the ready list, the scheduler will do the followings to run the highest priority task:

  1. Add the task into a ready list.
  2. Select a lowest priority running task core to yield. The core of the running task must be in the core map of the task. The logic is in prvYieldForTask function.
  3. The core calls prvSelectHighestPriorityTask to select next task from the ready list.

Step 1 and 2 are done in critical section.

So in the example, if the task with priority 8 is been put into the ready list, it will select task with priority 6 to yield. The precondition may also put this into consideration. However, your question is more about the purpose of the code snippet rather than the example. We should put more effort on the confusing point you mentioned.

Thank you for your elaboration. I will reply in this thread again later.

Thank you for your response.

  • Why is there a need to check here? Line 1076
    I take ur point, and the confusion is clear;

  • if( ( uxCoreMap & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U ) Line 1090
    The pxPreviousTCB is the previous currentTcb, and it just run on the core [xCoreID] a moment ago. So the condition expression is absolutely true, is it right?

  • why uxCoreMap &= ~( pxCurrentTCBs[ xCoreID ]->uxCoreAffinityMask )?
    In the formal code, I will comment the lines 1089-1103 at the function prvSelectHighestPriorityTask. For the uxCoreMap variable is zero at Line 1104 [https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/ae3a498e435cecdb25b889f2740ea99027dd0cb1/tasks.c], and prvYieldCore can not be invoked at prvSelectHighestPriorityTask. Do you think this is appropriate?

thanks again

if( ( uxCoreMap & ( ( UBaseType_t ) 1U << ( UBaseType_t ) xCoreID ) ) != 0U ) Line 1090
The pxPreviousTCB is the previous currentTcb, and it just run on the core [xCoreID] a moment ago. So the condition expression is absolutely true, is it right?

That is not true because a task can change its core affinity using vTaskCoreAffinitySet.

uxCoreMap &= ~( pxCurrentTCBs xCoreID ->uxCoreAffinityMask )

The above logic is to optimize the number of cores that we consider when finding a core for an evicted task.
Lets say the current state is the following:

Core Task Priority
0 A 2
1 B 5
2 C 6
3 D 7

Now task E with priority 3 becomes ready and needs to run. Task E has affinity
mask 1101 i.e. it can run on core 0, 2 and 3. We decide to evict task A from core 0.
At this point, we know that we did not evict task C and D from core 2 and 3 respectively,
even though task E could run on those cores as well. We can, therefore, conclude that
the priority of tasks running on core 2 and 3 is no lower than the priority of the task
running on core 0. More formally,

  • Task A is being evicted for Task E ==> Prio( A ) < Prio ( E )
  • Task C and D were not evicted for Task E ==> Prio( A ) <= Prio( C ), Prio( A ) <= Prio( D )

Therefore, when we want to find new home for task A, there is no point on going
to core 2 and 3 as those are already running tasks with priority no lower than task A.

1 Like

thank you very much. I will understand the content you mentioned.