Enable MSVC Port to leave the prvProcessSimulatedInterrupts loop when scheduler is stopped (#728)

* allow to leave loop

* add missing brace

* Code review suggestions

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>

---------

Signed-off-by: Gaurav Aggarwal <aggarg@amazon.com>
Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com>
Co-authored-by: Gaurav Aggarwal <aggarg@amazon.com>
pull/733/head^2
Ju1He1 2 years ago committed by GitHub
parent 8d80cf697a
commit 225bace85c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -340,6 +340,9 @@ SYSTEM_INFO xSystemInfo;
/* Start the first task. */
ResumeThread( pxThreadState->pvThread );
/* The scheduler is now running. */
xPortRunning = pdTRUE;
/* Handle all simulated interrupts - including yield requests and
simulated ticks. */
prvProcessSimulatedInterrupts();
@ -376,6 +379,8 @@ uint32_t ulSwitchRequired, i;
ThreadState_t *pxThreadState;
void *pvObjectList[ 2 ];
CONTEXT xContext;
DWORD xWinApiResult;
const DWORD xTimeoutMilliseconds = 1000;
/* Going to block on the mutex that ensured exclusive access to the simulated
interrupt objects, and the event that signals that a simulated interrupt
@ -388,105 +393,109 @@ CONTEXT xContext;
ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
SetEvent( pvInterruptEvent );
xPortRunning = pdTRUE;
for(;;)
while( xPortRunning == pdTRUE )
{
xInsideInterrupt = pdFALSE;
WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
/* Cannot be in a critical section to get here. Tasks that exit a
critical section will block on a yield mutex to wait for an interrupt to
process if an interrupt was set pending while the task was inside the
critical section. xInsideInterrupt prevents interrupts that contain
critical sections from doing the same. */
xInsideInterrupt = pdTRUE;
/* Used to indicate whether the simulated interrupt processing has
necessitated a context switch to another task/thread. */
ulSwitchRequired = pdFALSE;
/* For each interrupt we are interested in processing, each of which is
represented by a bit in the 32bit ulPendingInterrupts variable. */
for( i = 0; i < portMAX_INTERRUPTS; i++ )
/* Wait with timeout so that we can exit from this loop when
* the scheduler is stopped by calling vPortEndScheduler. */
xWinApiResult = WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, xTimeoutMilliseconds );
if( xWinApiResult != WAIT_TIMEOUT )
{
/* Is the simulated interrupt pending? */
if( ( ulPendingInterrupts & ( 1UL << i ) ) != 0 )
/* Cannot be in a critical section to get here. Tasks that exit a
critical section will block on a yield mutex to wait for an interrupt to
process if an interrupt was set pending while the task was inside the
critical section. xInsideInterrupt prevents interrupts that contain
critical sections from doing the same. */
xInsideInterrupt = pdTRUE;
/* Used to indicate whether the simulated interrupt processing has
necessitated a context switch to another task/thread. */
ulSwitchRequired = pdFALSE;
/* For each interrupt we are interested in processing, each of which is
represented by a bit in the 32bit ulPendingInterrupts variable. */
for( i = 0; i < portMAX_INTERRUPTS; i++ )
{
/* Is a handler installed? */
if( ulIsrHandler[ i ] != NULL )
/* Is the simulated interrupt pending? */
if( ( ulPendingInterrupts & ( 1UL << i ) ) != 0 )
{
/* Run the actual handler. Handlers return pdTRUE if they
necessitate a context switch. */
if( ulIsrHandler[ i ]() != pdFALSE )
/* Is a handler installed? */
if( ulIsrHandler[ i ] != NULL )
{
/* A bit mask is used purely to help debugging. */
ulSwitchRequired |= ( 1 << i );
/* Run the actual handler. Handlers return pdTRUE if they
necessitate a context switch. */
if( ulIsrHandler[ i ]() != pdFALSE )
{
/* A bit mask is used purely to help debugging. */
ulSwitchRequired |= ( 1 << i );
}
}
}
/* Clear the interrupt pending bit. */
ulPendingInterrupts &= ~( 1UL << i );
/* Clear the interrupt pending bit. */
ulPendingInterrupts &= ~( 1UL << i );
}
}
}
if( ulSwitchRequired != pdFALSE )
{
void *pvOldCurrentTCB;
if( ulSwitchRequired != pdFALSE )
{
void *pvOldCurrentTCB;
pvOldCurrentTCB = pxCurrentTCB;
pvOldCurrentTCB = pxCurrentTCB;
/* Select the next task to run. */
vTaskSwitchContext();
/* 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 );
/* 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
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
they do - so as they do not harm (slight run-time hit). */
xContext.ContextFlags = CONTEXT_INTEGER;
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
/* Obtain the state of the task now selected to enter the
Running state. */
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
/* pxThreadState->pvThread can be NULL if the task deleted
itself - but a deleted task should never be resumed here. */
configASSERT( pxThreadState->pvThread != NULL );
ResumeThread( pxThreadState->pvThread );
/* 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 );
/* 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
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
they do - so as they do not harm (slight run-time hit). */
xContext.ContextFlags = CONTEXT_INTEGER;
( void ) GetThreadContext( pxThreadState->pvThread, &xContext );
/* Obtain the state of the task now selected to enter the
Running state. */
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
/* pxThreadState->pvThread can be NULL if the task deleted
itself - but a deleted task should never be resumed here. */
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
(to ensure it does not continue running after the call to
SuspendThread() above as SuspendThread() is asynchronous).
Signal the event to ensure the thread can proceed now it is
valid for it to do so. Signaling the event is benign in the case that
the task was switched out asynchronously by an interrupt as the event
is reset before the task blocks on it. */
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
SetEvent( pxThreadState->pvYieldEvent );
ReleaseMutex( pvInterruptEventMutex );
/* If the thread that is about to be resumed stopped running
because it yielded then it will wait on an event when it resumed
(to ensure it does not continue running after the call to
SuspendThread() above as SuspendThread() is asynchronous).
Signal the event to ensure the thread can proceed now it is
valid for it to do so. Signaling the event is benign in the case that
the task was switched out asynchronously by an interrupt as the event
is reset before the task blocks on it. */
pxThreadState = ( ThreadState_t * ) ( *( size_t *) pxCurrentTCB );
SetEvent( pxThreadState->pvYieldEvent );
ReleaseMutex( pvInterruptEventMutex );
}
}
}
/*-----------------------------------------------------------*/

Loading…
Cancel
Save