Work on Win32 port layer - removing the need to store the critical section nesting count as part of the Win32 thread context.

This commit is contained in:
Richard Barry 2010-11-19 22:37:02 +00:00
parent 8133188eee
commit ab2eb016c1

View File

@ -91,9 +91,6 @@ typedef struct
section while pseudo interrupts were pending. */ section while pseudo interrupts were pending. */
long lWaitingInterruptAck; long lWaitingInterruptAck;
/* Critical nesting count of the task - each task has its own. */
portSTACK_TYPE ulCriticalNesting;
/* Handle of the thread that executes the task. */ /* Handle of the thread that executes the task. */
void * pvThread; void * pvThread;
} xThreadState; } xThreadState;
@ -154,13 +151,20 @@ static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
WaitForSingleObject( pvInterruptEventMutex, INFINITE ); WaitForSingleObject( pvInterruptEventMutex, INFINITE );
vPortTrace( "prvSimulatedPeripheralTimer: Got interrupt event mutex\r\n" ); vPortTrace( "prvSimulatedPeripheralTimer: Got interrupt event mutex\r\n" );
/* A thread will hold the interrupt event mutex while in a critical
section, so ulCriticalSection should be zero for this tick event to be
possible. */
if( ulCriticalNesting != 0 )
{
/* For a break point only. */
__asm{ NOP };
}
/* The timer has expired, generate the simulated tick event. */ /* The timer has expired, generate the simulated tick event. */
ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK ); ulPendingInterrupts |= ( 1 << portINTERRUPT_TICK );
/* The interrupt is now pending - but should only be processed if /* The interrupt is now pending - notify the simulated interrupt
interrupts are actually enabled. */ handler thread. */
if( ulCriticalNesting == 0UL )
{
vPortTrace( "prvSimulatedPeripheralTimer: Setting interrupt event to signal tick\r\n" ); vPortTrace( "prvSimulatedPeripheralTimer: Setting interrupt event to signal tick\r\n" );
SetEvent( pvInterruptEvent ); SetEvent( pvInterruptEvent );
@ -171,11 +175,6 @@ static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )
vPortTrace( "prvSimulatedPeripheralTimer: Releasing interrupt event mutex so tick can be processed\r\n" ); vPortTrace( "prvSimulatedPeripheralTimer: Releasing interrupt event mutex so tick can be processed\r\n" );
SignalObjectAndWait( pvInterruptEventMutex, pvTickAcknowledgeEvent, INFINITE, FALSE ); SignalObjectAndWait( pvInterruptEventMutex, pvTickAcknowledgeEvent, INFINITE, FALSE );
} }
else
{
ReleaseMutex( pvInterruptEventMutex );
}
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -194,7 +193,6 @@ xThreadState *pxThreadState = NULL;
/* Create the thread itself. */ /* Create the thread itself. */
pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL ); pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE ); SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
pxThreadState->ulCriticalNesting = portNO_CRITICAL_NESTING;
pxThreadState->lWaitingInterruptAck = pdFALSE; pxThreadState->lWaitingInterruptAck = pdFALSE;
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE ); SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
@ -296,6 +294,15 @@ unsigned long i;
WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE ); WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );
vPortTrace( "prvProcessPseudoInterrupts: Got interrupt event and mutex\r\n" ); vPortTrace( "prvProcessPseudoInterrupts: Got interrupt event and mutex\r\n" );
/* A thread will hold the interrupt event mutex while in a critical
section, so this pseudo interrupt handler should only run when
critical nesting is zero. */
if( ulCriticalNesting != 0 )
{
/* For a break point only. */
__asm{ NOP };
}
/* Used to indicate whether the pseudo interrupt processing has /* Used to indicate whether the pseudo interrupt processing has
necessitated a context switch to another task/thread. */ necessitated a context switch to another task/thread. */
lSwitchRequired = pdFALSE; lSwitchRequired = pdFALSE;
@ -331,8 +338,6 @@ unsigned long i;
set up to process yields while within a critical set up to process yields while within a critical
section. */ section. */
vPortTrace( "prvProcessPseudoInterrupts: Processing tick event\r\n" ); vPortTrace( "prvProcessPseudoInterrupts: Processing tick event\r\n" );
if( ulCriticalNesting == 0UL )
{
/* Process the tick itself. */ /* Process the tick itself. */
vPortTrace( "prvProcessPseudoInterrupts: Incrementing tick\r\n" ); vPortTrace( "prvProcessPseudoInterrupts: Incrementing tick\r\n" );
vTaskIncrementTick(); vTaskIncrementTick();
@ -350,19 +355,10 @@ unsigned long i;
vPortTrace( "prvProcessPseudoInterrupts: Acking tick\r\n" ); vPortTrace( "prvProcessPseudoInterrupts: Acking tick\r\n" );
SetEvent( pvTickAcknowledgeEvent ); SetEvent( pvTickAcknowledgeEvent );
}
else
{
/* The tick is held pending in ulCriticalNesting
until such time that pseudo interrupts are enabled
again. */
}
break; break;
default: default:
if( ulCriticalNesting == 0UL )
{
/* Is a handler installed? */ /* Is a handler installed? */
if( vIsrHandler[ i ] != NULL ) if( vIsrHandler[ i ] != NULL )
{ {
@ -378,7 +374,6 @@ unsigned long i;
event here for non-tick and none yield event here for non-tick and none yield
interrupts. */ interrupts. */
} }
}
break; break;
} }
} }
@ -390,10 +385,6 @@ unsigned long i;
pvOldCurrentTCB = pxCurrentTCB; pvOldCurrentTCB = pxCurrentTCB;
/* Save the state of the current thread before suspending it. */
pxThreadState = ( xThreadState *) *( ( unsigned long * ) pxCurrentTCB );
pxThreadState->ulCriticalNesting = ulCriticalNesting ;
/* Select the next task to run. */ /* Select the next task to run. */
vTaskSwitchContext(); vTaskSwitchContext();
@ -402,28 +393,40 @@ unsigned long i;
if( pvOldCurrentTCB != pxCurrentTCB ) if( pvOldCurrentTCB != pxCurrentTCB )
{ {
/* Suspend the old thread. */ /* Suspend the old thread. */
pxThreadState = ( xThreadState *) *( ( unsigned long * ) pvOldCurrentTCB );
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE ); SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
SuspendThread( pxThreadState->pvThread ); SuspendThread( pxThreadState->pvThread );
/* NOTE! - Here lies a problem when the preemptive scheduler is
used. It would seem Win32 threads do not stop as soon as a
call to suspend them is made. The co-operative scheduler gets
around this by having the thread block on a semaphore
immediately after yielding so it cannot execute any more task
code until it is once again scheduled to run. This cannot be
done if the task is pre-empted though, and I have not found an
equivalent work around for the preemptive situation. */
//sprintf( cTraceBuffer, "Event processor: suspending %s, resuming %s\r\n", ((xTCB*)pvOldCurrentTCB)->pcTaskName, ((xTCB*)pxCurrentTCB)->pcTaskName ); //sprintf( cTraceBuffer, "Event processor: suspending %s, resuming %s\r\n", ((xTCB*)pvOldCurrentTCB)->pcTaskName, ((xTCB*)pxCurrentTCB)->pcTaskName );
//vPortTrace( cTraceBuffer ); //vPortTrace( cTraceBuffer );
/* Obtain the state of the task now selected to enter the Running state. */ /* Obtain the state of the task now selected to enter the
Running state. */
pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB ); pxThreadState = ( xThreadState * ) ( *( unsigned long *) pxCurrentTCB );
ulCriticalNesting = pxThreadState->ulCriticalNesting;
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
ResumeThread( pxThreadState->pvThread );
if( pxThreadState->lWaitingInterruptAck == pdTRUE ) /* Boost the priority of the thread selected to run a little
{ in an attempt to get the Windows thread scheduler to act a
pxThreadState->lWaitingInterruptAck = pdFALSE; little more like an embedded engineer might expect. */
vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt\r\n" ); SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );
SetEvent( pvInterruptAcknowledgeEvent ); SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );
ResumeThread( pxThreadState->pvThread );
} }
} }
}
else
{
/* On exiting a critical section a task may have blocked on the /* On exiting a critical section a task may have blocked on the
interrupt event when only a tick needed processing, in which case interrupt event when only a tick needed processing, in which case
it will not have been released from waiting on the event yet. */ it will not have been released from waiting on the event yet. */
@ -434,7 +437,6 @@ unsigned long i;
vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt even though a yield has not been performed.\r\n" ); vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt even though a yield has not been performed.\r\n" );
SetEvent( pvInterruptAcknowledgeEvent ); SetEvent( pvInterruptAcknowledgeEvent );
} }
}
ReleaseMutex( pvInterruptEventMutex ); ReleaseMutex( pvInterruptEventMutex );
} }
@ -456,7 +458,10 @@ xThreadState *pxThreadState;
WaitForSingleObject( pvInterruptEventMutex, INFINITE ); WaitForSingleObject( pvInterruptEventMutex, INFINITE );
ulPendingInterrupts |= ( 1 << ulInterruptNumber ); ulPendingInterrupts |= ( 1 << ulInterruptNumber );
if( ulCriticalNesting == 0 ) //|| ( ulInterruptNumber == portINTERRUPT_YIELD ) ) /* The pseudo interrupt is now held pending, but don't actually process it
yet if this call is within a critical section. It is possible for this to
be in a critical section as calls to wait for mutexes are accumulative. */
if( ulCriticalNesting == 0 )
{ {
/* The event handler needs to know to signal the interrupt acknowledge event /* The event handler needs to know to signal the interrupt acknowledge event
the next time this task runs. */ the next time this task runs. */
@ -475,12 +480,7 @@ xThreadState *pxThreadState;
} }
SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE ); SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
vPortTrace( "vPortGeneratePseudoInterrupt: About to release interrupt event mutex\r\n" );
// ReleaseMutex( pvInterruptEventMutex );
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for interrupt ack\r\n" ); vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for interrupt ack\r\n" );
// WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt acknowledged, leaving vPortGeneratePseudoInterrupt()\r\n" );
} }
else else
{ {
@ -512,10 +512,10 @@ void vPortEnterCritical( void )
{ {
if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED )
{ {
/* The interrupt event mutex is held for the entire critical section,
effectively disabling (pseudo) interrupts. */
WaitForSingleObject( pvInterruptEventMutex, INFINITE ); WaitForSingleObject( pvInterruptEventMutex, INFINITE );
// SuspendThread( pvSimulatedTimerThread );
ulCriticalNesting++; ulCriticalNesting++;
ReleaseMutex( pvInterruptEventMutex );
} }
else else
{ {
@ -527,21 +527,17 @@ void vPortEnterCritical( void )
void vPortExitCritical( void ) void vPortExitCritical( void )
{ {
xThreadState *pxThreadState; xThreadState *pxThreadState;
long lMutexNeedsReleasing;
/* The interrupt event mutex should already be held by this thread as it was
obtained on entry to the critical section. */
lMutexNeedsReleasing = pdTRUE;
if( ulCriticalNesting > portNO_CRITICAL_NESTING ) if( ulCriticalNesting > portNO_CRITICAL_NESTING )
{ {
if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) ) if( ulCriticalNesting == ( portNO_CRITICAL_NESTING + 1 ) )
{ {
/* Wait for the interrupt event mutex prior to manipulating or
testing the pseudo interrupt control variables. */
WaitForSingleObject( pvInterruptEventMutex, INFINITE );
vPortTrace( "vPortExitCritical: Got interrupt event mutex\r\n" );
// ResumeThread( pvSimulatedTimerThread );
/* Now it is safe to decrement the critical nesting count as no
tick events will be processed until the interrupt event mutex is
given back. */
ulCriticalNesting--; ulCriticalNesting--;
/* Were any interrupts set to pending while interrupts were /* Were any interrupts set to pending while interrupts were
@ -550,33 +546,17 @@ xThreadState *pxThreadState;
{ {
SetEvent( pvInterruptEvent ); SetEvent( pvInterruptEvent );
/* The interrupt ack event should not be signaled yet - if it
is then there is an error in the logical simulation. */
if( WaitForSingleObject( pvInterruptAcknowledgeEvent, 0 ) != WAIT_TIMEOUT )
{
/* This line is for a break point only. */
__asm { NOP };
}
/* The event handler needs to know to signal the interrupt /* The event handler needs to know to signal the interrupt
acknowledge event the next time this task runs. */ acknowledge event the next time this task runs. */
pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB ); pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
pxThreadState->lWaitingInterruptAck = pdTRUE; pxThreadState->lWaitingInterruptAck = pdTRUE;
/* Mutex will be released now, so does not require releasing
on function exit. */
lMutexNeedsReleasing = pdFALSE;
SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE ); SignalObjectAndWait( pvInterruptEventMutex, pvInterruptAcknowledgeEvent, INFINITE, FALSE );
/* Give back the interrupt event mutex so the event can be processed. */
// ReleaseMutex( pvInterruptEventMutex );
// vPortTrace( "vPortExitCritical: Waiting interrupt ack\r\n" );
// WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );
vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" ); vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" );
} }
else
{
/* Can't leave here without giving back the interrupt event
mutex. */
ReleaseMutex( pvInterruptEventMutex );
}
} }
else else
{ {
@ -585,4 +565,9 @@ xThreadState *pxThreadState;
ulCriticalNesting--; ulCriticalNesting--;
} }
} }
if( lMutexNeedsReleasing == pdTRUE )
{
ReleaseMutex( pvInterruptEventMutex );
}
} }