mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-19 21:11:57 -04:00
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:
parent
29b202a41e
commit
2e0c623351
|
@ -435,32 +435,13 @@ static void prvProcessSimulatedInterrupts( void )
|
||||||
|
|
||||||
if( ulSwitchRequired != pdFALSE )
|
if( ulSwitchRequired != pdFALSE )
|
||||||
{
|
{
|
||||||
void * pvOldCurrentTCB;
|
/* Suspend the old thread. */
|
||||||
|
pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pxCurrentTCB );
|
||||||
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 );
|
|
||||||
SuspendThread( pxThreadState->pvThread );
|
SuspendThread( pxThreadState->pvThread );
|
||||||
|
|
||||||
/* Ensure the thread is actually suspended by performing a
|
/* Ensure the thread is actually suspended by performing a
|
||||||
* synchronous operation that can only complete when the thread is
|
* synchronous operation that can only complete when the thread
|
||||||
* actually suspended. The below code asks for dummy register
|
* is actually suspended. The below code asks for dummy register
|
||||||
* data. Experimentation shows that these two lines don't appear
|
* data. Experimentation shows that these two lines don't appear
|
||||||
* to do anything now, but according to
|
* to do anything now, but according to
|
||||||
* https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743
|
* https://devblogs.microsoft.com/oldnewthing/20150205-00/?p=44743
|
||||||
|
@ -468,6 +449,9 @@ static void prvProcessSimulatedInterrupts( void )
|
||||||
xContext.ContextFlags = CONTEXT_INTEGER;
|
xContext.ContextFlags = CONTEXT_INTEGER;
|
||||||
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
|
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
|
||||||
|
|
||||||
|
/* Select the next task to run. */
|
||||||
|
vTaskSwitchContext();
|
||||||
|
|
||||||
/* Obtain the state of the task now selected to enter the
|
/* Obtain the state of the task now selected to enter the
|
||||||
* Running state. */
|
* Running state. */
|
||||||
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pxCurrentTCB );
|
pxThreadState = ( ThreadState_t * ) ( *( size_t * ) pxCurrentTCB );
|
||||||
|
@ -477,7 +461,6 @@ static void prvProcessSimulatedInterrupts( void )
|
||||||
configASSERT( pxThreadState->pvThread != NULL );
|
configASSERT( pxThreadState->pvThread != NULL );
|
||||||
ResumeThread( pxThreadState->pvThread );
|
ResumeThread( pxThreadState->pvThread );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* If the thread that is about to be resumed stopped running
|
/* If the thread that is about to be resumed stopped running
|
||||||
* because it yielded then it will wait on an event when it resumed
|
* because it yielded then it will wait on an event when it resumed
|
||||||
|
|
Loading…
Reference in a new issue