mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2026-05-12 11:42:57 -04:00
Fix SMP scheduler evicting task when preemption is disabled
In the SMP time-slicing path of xTaskIncrementTick(), xYieldPendings[] was set unconditionally without checking xPreemptionDisable. Although the yield-processing block correctly skipped acting on it for cores with preemption disabled, the stale flag remained and was later misinterpreted by FromISR functions (xTaskGenericNotifyFromISR, xTaskResumeFromISR, etc.) that use xYieldPendings as a proxy for whether prvYieldForTask() decided to yield. This caused *pxHigherPriorityTaskWoken to be erroneously set to pdTRUE, triggering portYIELD_FROM_ISR() and ultimately evicting the preemption-disabled task via prvSelectHighestPriorityTask(). Three-layer fix: 1. Root cause: Guard the time-slicing xYieldPendings[] assignment in xTaskIncrementTick() with a configUSE_TASK_PREEMPTION_DISABLE check so the flag is never set for cores running preemption-disabled tasks. 2. Defense in depth: In the four functions that check xYieldPendings[] after prvYieldForTask() (xTaskResumeFromISR, xTaskRemoveFromEventList, xTaskGenericNotifyFromISR, vTaskGenericNotifyGiveFromISR), save the value before the call and only report a yield if it transitioned from pdFALSE to pdTRUE, eliminating false positives from stale flags. 3. Safety net: Add a preemption-disable check in the SMP vTaskSwitchContext(), analogous to the existing uxSchedulerSuspended check. If a context switch is somehow triggered for a core whose current task has preemption disabled, the switch is deferred by setting xYieldPendings and will execute when vTaskPreemptionEnable() is called. Closes #1376 Made-with: Cursor
This commit is contained in:
parent
f1043c49d5
commit
c926adcf6e
1 changed files with 32 additions and 5 deletions
35
tasks.c
35
tasks.c
|
|
@ -3524,9 +3524,12 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
|||
|
||||
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PREEMPTION == 1 ) )
|
||||
{
|
||||
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||
|
||||
prvYieldForTask( pxTCB );
|
||||
|
||||
if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
|
||||
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||
( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE ) )
|
||||
{
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
|
|
@ -4889,9 +4892,14 @@ BaseType_t xTaskIncrementTick( void )
|
|||
for( xCoreID = 0; xCoreID < ( ( BaseType_t ) configNUMBER_OF_CORES ); xCoreID++ )
|
||||
{
|
||||
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ xCoreID ]->uxPriority ] ) ) > 1U )
|
||||
{
|
||||
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||
if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE )
|
||||
#endif
|
||||
{
|
||||
xYieldPendings[ xCoreID ] = pdTRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
|
|
@ -5222,6 +5230,16 @@ BaseType_t xTaskIncrementTick( void )
|
|||
* SMP port. */
|
||||
configASSERT( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 );
|
||||
|
||||
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||
if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable != pdFALSE )
|
||||
{
|
||||
/* The current task has preemption disabled - do not allow a
|
||||
* context switch. The yield will be performed when preemption
|
||||
* is re-enabled. */
|
||||
xYieldPendings[ xCoreID ] = pdTRUE;
|
||||
}
|
||||
else
|
||||
#endif /* #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) */
|
||||
if( uxSchedulerSuspended != ( UBaseType_t ) 0U )
|
||||
{
|
||||
/* The scheduler is currently suspended - do not allow a context
|
||||
|
|
@ -5479,9 +5497,12 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
|
|||
|
||||
#if ( configUSE_PREEMPTION == 1 )
|
||||
{
|
||||
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||
|
||||
prvYieldForTask( pxUnblockedTCB );
|
||||
|
||||
if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
|
||||
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||
( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE ) )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
|
@ -8190,9 +8211,12 @@ TickType_t uxTaskResetEventItemValue( void )
|
|||
{
|
||||
#if ( configUSE_PREEMPTION == 1 )
|
||||
{
|
||||
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||
|
||||
prvYieldForTask( pxTCB );
|
||||
|
||||
if( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE )
|
||||
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||
( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE ) )
|
||||
{
|
||||
if( pxHigherPriorityTaskWoken != NULL )
|
||||
{
|
||||
|
|
@ -8324,9 +8348,12 @@ TickType_t uxTaskResetEventItemValue( void )
|
|||
{
|
||||
#if ( configUSE_PREEMPTION == 1 )
|
||||
{
|
||||
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||
|
||||
prvYieldForTask( pxTCB );
|
||||
|
||||
if( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE )
|
||||
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||
( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE ) )
|
||||
{
|
||||
if( pxHigherPriorityTaskWoken != NULL )
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue