Fix race in prvProcessSimulatedInterrupts (#1055)

Earlier the code was suspending the current thread after calling
vTaskSwitchContext. This left a gap where the current thread could
access incorrect pxCurrentTCB after it was changed by
vTaskSwitchContext.

This commit addresses the problem by suspending the current thread
before calling vTaskSwitchContext.

It was reported here - https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/1054.

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
This commit is contained in:
Gaurav-Aggarwal-AWS 2024-05-14 16:15:54 +05:30 committed by GitHub
parent 29b202a41e
commit 2e0c623351
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -435,32 +435,13 @@ static void prvProcessSimulatedInterrupts( void )
if( ulSwitchRequired != pdFALSE )
{
void * pvOldCurrentTCB;
pvOldCurrentTCB = pxCurrentTCB;
/* Select the next task to run. */
vTaskSwitchContext();
/* If the task selected to enter the running state is not the task
* that is already in the running state. */
if( pvOldCurrentTCB != pxCurrentTCB )
{
/* Suspend the old thread. In the cases where the (simulated)
* interrupt is asynchronous (tick event swapping a task out rather
* than a task blocking or yielding) it doesn't matter if the
* 'suspend' operation doesn't take effect immediately - if it
* doesn't it would just be like the interrupt occurring slightly
* later. In cases where the yield was caused by a task blocking
* or yielding then the task will block on a yield event after the
* yield operation in case the 'suspend' operation doesn't take
* effect immediately. */
pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pvOldCurrentTCB );
/* Suspend the old thread. */
pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pxCurrentTCB );
SuspendThread( pxThreadState->pvThread );
/* Ensure the thread is actually suspended by performing a
* synchronous operation that can only complete when the thread is
* actually suspended. The below code asks for dummy register
* synchronous operation that can only complete when the thread
* is actually suspended. The below code asks for dummy register
* data. Experimentation shows that these two lines don't appear
* to do anything now, but according to
* https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743
@ -468,6 +449,9 @@ static void prvProcessSimulatedInterrupts( void )
xContext.ContextFlags = CONTEXT_INTEGER;
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
/* Select the next task to run. */
vTaskSwitchContext();
/* Obtain the state of the task now selected to enter the
* Running state. */
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pxCurrentTCB );
@ -477,7 +461,6 @@ static void prvProcessSimulatedInterrupts( void )
configASSERT( pxThreadState->pvThread != NULL );
ResumeThread( pxThreadState->pvThread );
}
}
/* If the thread that is about to be resumed stopped running
* because it yielded then it will wait on an event when it resumed