Skip to content

Commit 57a5ed7

Browse files
chinglee-iotaggarg
andauthored
Fix SMP task self void run state change (FreeRTOS#984)
* Request a task to yield after been suspended or deleted to prevent this task puts itself back to another list * Fix volatile variable access order to ensure ensure compliance with MISRA C 2012 Rule 13.5 --------- Signed-off-by: Gaurav Aggarwal <[email protected]> Co-authored-by: Gaurav Aggarwal <[email protected]>
1 parent 23afc48 commit 57a5ed7

File tree

1 file changed

+87
-76
lines changed

1 file changed

+87
-76
lines changed

tasks.c

Lines changed: 87 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -2191,6 +2191,7 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
21912191
{
21922192
TCB_t * pxTCB;
21932193
BaseType_t xDeleteTCBInIdleTask = pdFALSE;
2194+
BaseType_t xTaskIsRunningOrYielding;
21942195

21952196
traceENTER_vTaskDelete( xTaskToDelete );
21962197

@@ -2226,10 +2227,15 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
22262227
* not return. */
22272228
uxTaskNumber++;
22282229

2230+
/* Use temp variable as distinct sequence points for reading volatile
2231+
* variables prior to a logical operator to ensure compliance with
2232+
* MISRA C 2012 Rule 13.5. */
2233+
xTaskIsRunningOrYielding = taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD( pxTCB );
2234+
22292235
/* If the task is running (or yielding), we must add it to the
22302236
* termination list so that an idle task can delete it when it is
22312237
* no longer running. */
2232-
if( ( xSchedulerRunning != pdFALSE ) && ( taskTASK_IS_RUNNING_OR_SCHEDULED_TO_YIELD( pxTCB ) != pdFALSE ) )
2238+
if( ( xSchedulerRunning != pdFALSE ) && ( xTaskIsRunningOrYielding != pdFALSE ) )
22332239
{
22342240
/* A running task or a task which is scheduled to yield is being
22352241
* deleted. This cannot complete when the task is still running
@@ -2261,6 +2267,30 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
22612267
#else
22622268
portPRE_TASK_DELETE_HOOK( pxTCB, &( xYieldPendings[ pxTCB->xTaskRunState ] ) );
22632269
#endif
2270+
2271+
/* In the case of SMP, it is possible that the task being deleted
2272+
* is running on another core. We must evict the task before
2273+
* exiting the critical section to ensure that the task cannot
2274+
* take an action which puts it back on ready/state/event list,
2275+
* thereby nullifying the delete operation. Once evicted, the
2276+
* task won't be scheduled ever as it will no longer be on the
2277+
* ready list. */
2278+
#if ( configNUMBER_OF_CORES > 1 )
2279+
{
2280+
if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
2281+
{
2282+
if( pxTCB->xTaskRunState == ( BaseType_t ) portGET_CORE_ID() )
2283+
{
2284+
configASSERT( uxSchedulerSuspended == 0 );
2285+
taskYIELD_WITHIN_API();
2286+
}
2287+
else
2288+
{
2289+
prvYieldCore( pxTCB->xTaskRunState );
2290+
}
2291+
}
2292+
}
2293+
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
22642294
}
22652295
else
22662296
{
@@ -2284,9 +2314,9 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
22842314

22852315
/* Force a reschedule if it is the currently running task that has just
22862316
* been deleted. */
2287-
if( xSchedulerRunning != pdFALSE )
2317+
#if ( configNUMBER_OF_CORES == 1 )
22882318
{
2289-
#if ( configNUMBER_OF_CORES == 1 )
2319+
if( xSchedulerRunning != pdFALSE )
22902320
{
22912321
if( pxTCB == pxCurrentTCB )
22922322
{
@@ -2298,30 +2328,8 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
22982328
mtCOVERAGE_TEST_MARKER();
22992329
}
23002330
}
2301-
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
2302-
{
2303-
/* It is important to use critical section here because
2304-
* checking run state of a task must be done inside a
2305-
* critical section. */
2306-
taskENTER_CRITICAL();
2307-
{
2308-
if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
2309-
{
2310-
if( pxTCB->xTaskRunState == ( BaseType_t ) portGET_CORE_ID() )
2311-
{
2312-
configASSERT( uxSchedulerSuspended == 0 );
2313-
taskYIELD_WITHIN_API();
2314-
}
2315-
else
2316-
{
2317-
prvYieldCore( pxTCB->xTaskRunState );
2318-
}
2319-
}
2320-
}
2321-
taskEXIT_CRITICAL();
2322-
}
2323-
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
23242331
}
2332+
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
23252333

23262334
traceRETURN_vTaskDelete();
23272335
}
@@ -3155,26 +3163,66 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
31553163
}
31563164
}
31573165
#endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
3158-
}
3159-
taskEXIT_CRITICAL();
31603166

3161-
if( xSchedulerRunning != pdFALSE )
3162-
{
3163-
/* Reset the next expected unblock time in case it referred to the
3164-
* task that is now in the Suspended state. */
3165-
taskENTER_CRITICAL();
3167+
/* In the case of SMP, it is possible that the task being suspended
3168+
* is running on another core. We must evict the task before
3169+
* exiting the critical section to ensure that the task cannot
3170+
* take an action which puts it back on ready/state/event list,
3171+
* thereby nullifying the suspend operation. Once evicted, the
3172+
* task won't be scheduled before it is resumed as it will no longer
3173+
* be on the ready list. */
3174+
#if ( configNUMBER_OF_CORES > 1 )
31663175
{
3167-
prvResetNextTaskUnblockTime();
3176+
if( xSchedulerRunning != pdFALSE )
3177+
{
3178+
/* Reset the next expected unblock time in case it referred to the
3179+
* task that is now in the Suspended state. */
3180+
prvResetNextTaskUnblockTime();
3181+
3182+
if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
3183+
{
3184+
if( pxTCB->xTaskRunState == ( BaseType_t ) portGET_CORE_ID() )
3185+
{
3186+
/* The current task has just been suspended. */
3187+
configASSERT( uxSchedulerSuspended == 0 );
3188+
vTaskYieldWithinAPI();
3189+
}
3190+
else
3191+
{
3192+
prvYieldCore( pxTCB->xTaskRunState );
3193+
}
3194+
}
3195+
else
3196+
{
3197+
mtCOVERAGE_TEST_MARKER();
3198+
}
3199+
}
3200+
else
3201+
{
3202+
mtCOVERAGE_TEST_MARKER();
3203+
}
31683204
}
3169-
taskEXIT_CRITICAL();
3170-
}
3171-
else
3172-
{
3173-
mtCOVERAGE_TEST_MARKER();
3205+
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
31743206
}
3207+
taskEXIT_CRITICAL();
31753208

31763209
#if ( configNUMBER_OF_CORES == 1 )
31773210
{
3211+
if( xSchedulerRunning != pdFALSE )
3212+
{
3213+
/* Reset the next expected unblock time in case it referred to the
3214+
* task that is now in the Suspended state. */
3215+
taskENTER_CRITICAL();
3216+
{
3217+
prvResetNextTaskUnblockTime();
3218+
}
3219+
taskEXIT_CRITICAL();
3220+
}
3221+
else
3222+
{
3223+
mtCOVERAGE_TEST_MARKER();
3224+
}
3225+
31783226
if( pxTCB == pxCurrentTCB )
31793227
{
31803228
if( xSchedulerRunning != pdFALSE )
@@ -3207,43 +3255,6 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
32073255
mtCOVERAGE_TEST_MARKER();
32083256
}
32093257
}
3210-
#else /* #if ( configNUMBER_OF_CORES == 1 ) */
3211-
{
3212-
/* Enter critical section here to check run state of a task. */
3213-
taskENTER_CRITICAL();
3214-
{
3215-
if( taskTASK_IS_RUNNING( pxTCB ) == pdTRUE )
3216-
{
3217-
if( xSchedulerRunning != pdFALSE )
3218-
{
3219-
if( pxTCB->xTaskRunState == ( BaseType_t ) portGET_CORE_ID() )
3220-
{
3221-
/* The current task has just been suspended. */
3222-
configASSERT( uxSchedulerSuspended == 0 );
3223-
vTaskYieldWithinAPI();
3224-
}
3225-
else
3226-
{
3227-
prvYieldCore( pxTCB->xTaskRunState );
3228-
}
3229-
}
3230-
else
3231-
{
3232-
/* This code path is not possible because only Idle tasks are
3233-
* assigned a core before the scheduler is started ( i.e.
3234-
* taskTASK_IS_RUNNING is only true for idle tasks before
3235-
* the scheduler is started ) and idle tasks cannot be
3236-
* suspended. */
3237-
mtCOVERAGE_TEST_MARKER();
3238-
}
3239-
}
3240-
else
3241-
{
3242-
mtCOVERAGE_TEST_MARKER();
3243-
}
3244-
}
3245-
taskEXIT_CRITICAL();
3246-
}
32473258
#endif /* #if ( configNUMBER_OF_CORES == 1 ) */
32483259

32493260
traceRETURN_vTaskSuspend();

0 commit comments

Comments
 (0)