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
37
tasks.c
37
tasks.c
|
|
@ -3524,9 +3524,12 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
||||||
|
|
||||||
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PREEMPTION == 1 ) )
|
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PREEMPTION == 1 ) )
|
||||||
{
|
{
|
||||||
|
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||||
|
|
||||||
prvYieldForTask( pxTCB );
|
prvYieldForTask( pxTCB );
|
||||||
|
|
||||||
if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
|
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||||
|
( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE ) )
|
||||||
{
|
{
|
||||||
xYieldRequired = pdTRUE;
|
xYieldRequired = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -4890,7 +4893,12 @@ BaseType_t xTaskIncrementTick( void )
|
||||||
{
|
{
|
||||||
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ xCoreID ]->uxPriority ] ) ) > 1U )
|
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCBs[ xCoreID ]->uxPriority ] ) ) > 1U )
|
||||||
{
|
{
|
||||||
xYieldPendings[ xCoreID ] = pdTRUE;
|
#if ( configUSE_TASK_PREEMPTION_DISABLE == 1 )
|
||||||
|
if( pxCurrentTCBs[ xCoreID ]->xPreemptionDisable == pdFALSE )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
xYieldPendings[ xCoreID ] = pdTRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -5222,6 +5230,16 @@ BaseType_t xTaskIncrementTick( void )
|
||||||
* SMP port. */
|
* SMP port. */
|
||||||
configASSERT( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 );
|
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 )
|
if( uxSchedulerSuspended != ( UBaseType_t ) 0U )
|
||||||
{
|
{
|
||||||
/* The scheduler is currently suspended - do not allow a context
|
/* 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 )
|
#if ( configUSE_PREEMPTION == 1 )
|
||||||
{
|
{
|
||||||
|
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||||
|
|
||||||
prvYieldForTask( pxUnblockedTCB );
|
prvYieldForTask( pxUnblockedTCB );
|
||||||
|
|
||||||
if( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE )
|
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||||
|
( xYieldPendings[ portGET_CORE_ID() ] != pdFALSE ) )
|
||||||
{
|
{
|
||||||
xReturn = pdTRUE;
|
xReturn = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
@ -8190,9 +8211,12 @@ TickType_t uxTaskResetEventItemValue( void )
|
||||||
{
|
{
|
||||||
#if ( configUSE_PREEMPTION == 1 )
|
#if ( configUSE_PREEMPTION == 1 )
|
||||||
{
|
{
|
||||||
|
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||||
|
|
||||||
prvYieldForTask( pxTCB );
|
prvYieldForTask( pxTCB );
|
||||||
|
|
||||||
if( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE )
|
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||||
|
( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE ) )
|
||||||
{
|
{
|
||||||
if( pxHigherPriorityTaskWoken != NULL )
|
if( pxHigherPriorityTaskWoken != NULL )
|
||||||
{
|
{
|
||||||
|
|
@ -8324,9 +8348,12 @@ TickType_t uxTaskResetEventItemValue( void )
|
||||||
{
|
{
|
||||||
#if ( configUSE_PREEMPTION == 1 )
|
#if ( configUSE_PREEMPTION == 1 )
|
||||||
{
|
{
|
||||||
|
BaseType_t xYieldPendingBefore = xYieldPendings[ portGET_CORE_ID() ];
|
||||||
|
|
||||||
prvYieldForTask( pxTCB );
|
prvYieldForTask( pxTCB );
|
||||||
|
|
||||||
if( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE )
|
if( ( xYieldPendingBefore == pdFALSE ) &&
|
||||||
|
( xYieldPendings[ portGET_CORE_ID() ] == pdTRUE ) )
|
||||||
{
|
{
|
||||||
if( pxHigherPriorityTaskWoken != NULL )
|
if( pxHigherPriorityTaskWoken != NULL )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue