Updated Win32 port layer so that end of interrupt events are only sent to threads that are actually waiting for them.

pull/1/head
Richard Barry 14 years ago
parent 9a0b608591
commit 93b07f3db7

@ -56,59 +56,7 @@
#include "task.h" #include "task.h"
#include <stdio.h> #include <stdio.h>
//FILE *pfTraceFile = NULL;
typedef struct xTaskControlBlock
{
volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
#endif
xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
#if ( portSTACK_GROWTH > 0 )
portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
unsigned portBASE_TYPE uxCriticalNesting;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
#endif
#if ( configUSE_MUTEXES == 1 )
unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
pdTASK_HOOK_CODE pxTaskTag;
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
#endif
} xTCB;
FILE *pfTraceFile = NULL;
//#define vPortTrace( x ) if( pfTraceFile == NULL ) pfTraceFile = fopen( "c:/temp/trace.txt", "w" ); if( pfTraceFile != NULL ) fprintf( pfTraceFile, x ) //#define vPortTrace( x ) if( pfTraceFile == NULL ) pfTraceFile = fopen( "c:/temp/trace.txt", "w" ); if( pfTraceFile != NULL ) fprintf( pfTraceFile, x )
#define vPortTrace( x ) ( void ) x #define vPortTrace( x ) ( void ) x
@ -137,16 +85,17 @@ the only thing it will ever hold. The structure indirectly maps the task handle
to a thread handle. */ to a thread handle. */
typedef struct typedef struct
{ {
portSTACK_TYPE ulCriticalNesting; /* Critical nesting count of the task. */ /* Set to true for tasks that call the generate psuedo interrupt function,
void * pvThread; /* Handle of the thread that executes the task. */ as the event handler needs to know whether to signal the interrupt ack
} xThreadState; event when the task next runs. */
long lWaitingInterruptAck;
/* The parameters passed to a thread when it is created. */ /* Critical nesting count of the task - each task has its own. */
typedef struct XPARAMS portSTACK_TYPE ulCriticalNesting;
{
pdTASK_CODE pxCode; /* The entry point of the task (rather than thread) code. */ /* Handle of the thread that executes the task. */
void *pvParameters; /* The parameters that are passed to the task (rather than thread. */ void * pvThread;
} xParams; } xThreadState;
/* Pseudo interrupts waiting to be processed. This is a bit mask where each /* Pseudo interrupts waiting to be processed. This is a bit mask where each
bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */ bit represents one interrupt, so a maximum of 32 interrupts can be simulated. */
@ -192,7 +141,6 @@ void *pvTimer;
LARGE_INTEGER liDueTime; LARGE_INTEGER liDueTime;
void *pvObjectList[ 2 ]; void *pvObjectList[ 2 ];
const long long ll_ms_In_100ns_units = ( long long ) -1000; const long long ll_ms_In_100ns_units = ( long long ) -1000;
extern volatile unsigned long ulTicks;
/* Just to prevent compiler warnings. */ /* Just to prevent compiler warnings. */
( void ) lpParameter; ( void ) lpParameter;
@ -213,8 +161,6 @@ extern volatile unsigned long ulTicks;
for(;;) for(;;)
{ {
ulTicks++;
/* The timer is reset on each itteration of this loop rather than being set /* The timer is reset on each itteration of this loop rather than being set
to function periodicallys - this is for the reasons stated in the comments to function periodicallys - this is for the reasons stated in the comments
where the timer is created. */ where the timer is created. */
@ -258,29 +204,20 @@ extern volatile unsigned long ulTicks;
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters ) portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{ {
xThreadState *pxThreadState = NULL; xThreadState *pxThreadState = NULL;
xParams *pxThreadParams = ( void * ) pvPortMalloc( sizeof( xParams ) );
if( pxThreadParams != NULL ) /* In this simulated case a stack is not initialised, but instead a thread
{ is created that will execute the task being created. The thread handles
/* In this simulated case a stack is not initialised, but instead a thread the context switching itself. The xThreadState object is placed onto
is created that will execute the task being created. The thread handles the stack that was created for the task - so the stack buffer is still
the context switching itself. The xThreadState object is placed onto used, just not in the conventional way. It will not be used for anything
the stack that was created for the task - so the stack buffer is still other than holding this structure. */
used, just not in the conventional way. It will not be used for anything pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );
other than holding this structure. */
pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );
/* The parameters that are passed into the thread so it knows how to
start the task executing. */
pxThreadParams->pxCode = pxCode;
pxThreadParams->pvParameters = pvParameters;
/* Create the thread itself. */ /* Create the thread itself. */
//pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) prvThreadEntryPoint, pxThreadParams, CREATE_SUSPENDED, NULL );
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 );
pxThreadState->ulCriticalNesting = portNO_CRITICAL_NESTING; pxThreadState->ulCriticalNesting = portNO_CRITICAL_NESTING;
pxThreadState->lWaitingInterruptAck = pdFALSE;
SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE ); SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );
}
return ( portSTACK_TYPE * ) pxThreadState; return ( portSTACK_TYPE * ) pxThreadState;
} }
@ -347,11 +284,11 @@ xThreadState *pxThreadState;
static void prvProcessEvents( void ) static void prvProcessEvents( void )
{ {
long lSwitchRequired, lAcknowledgeTick, lAcknowledgeInterrupt; long lSwitchRequired;
xThreadState *pxThreadState; xThreadState *pxThreadState;
void *pvObjectList[ 2 ]; void *pvObjectList[ 2 ];
unsigned long i; unsigned long i;
char cTraceBuffer[ 256 ]; //char cTraceBuffer[ 256 ];
vPortTrace( "Entering prvProcessEvents\r\n" ); vPortTrace( "Entering prvProcessEvents\r\n" );
@ -372,8 +309,6 @@ char cTraceBuffer[ 256 ];
//WaitForSingleObject( pvInterruptEventMutex, INFINITE ); //WaitForSingleObject( pvInterruptEventMutex, INFINITE );
lSwitchRequired = pdFALSE; lSwitchRequired = pdFALSE;
lAcknowledgeTick = pdFALSE;
lAcknowledgeInterrupt = pdFALSE;
/* For each interrupt we are interested in processing, each of which is /* For each interrupt we are interested in processing, each of which is
represented by a bit in the 32bit ulPendingInterrupts variable. */ represented by a bit in the 32bit ulPendingInterrupts variable. */
@ -392,8 +327,6 @@ char cTraceBuffer[ 256 ];
/* Clear the interrupt pending bit. */ /* Clear the interrupt pending bit. */
ulPendingInterrupts &= ~( 1UL << portINTERRUPT_YIELD ); ulPendingInterrupts &= ~( 1UL << portINTERRUPT_YIELD );
lAcknowledgeInterrupt = pdTRUE;
break; break;
case portINTERRUPT_TICK: case portINTERRUPT_TICK:
@ -415,7 +348,8 @@ char cTraceBuffer[ 256 ];
} }
#endif #endif
lAcknowledgeTick = pdTRUE; vPortTrace( "prvProcessEvents: Acking tick\r\n" );
SetEvent( pvTickAcknowledgeEvent );
/* Clear the interrupt pending bit. */ /* Clear the interrupt pending bit. */
ulPendingInterrupts &= ~( 1UL << portINTERRUPT_TICK ); ulPendingInterrupts &= ~( 1UL << portINTERRUPT_TICK );
@ -435,7 +369,8 @@ char cTraceBuffer[ 256 ];
/* Clear the interrupt pending bit. */ /* Clear the interrupt pending bit. */
ulPendingInterrupts &= ~( 1UL << i ); ulPendingInterrupts &= ~( 1UL << i );
lAcknowledgeInterrupt = pdTRUE; /* TODO: Need to have some sort of handshake event here for non-tick
and none yield interrupts. */
} }
break; break;
} }
@ -461,27 +396,21 @@ char cTraceBuffer[ 256 ];
{ {
/* Suspend the old thread. */ /* Suspend the old thread. */
SuspendThread( pxThreadState->pvThread ); SuspendThread( pxThreadState->pvThread );
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; ulCriticalNesting = pxThreadState->ulCriticalNesting;
ResumeThread( pxThreadState->pvThread ); ResumeThread( pxThreadState->pvThread );
}
}
/* Was a tick processed? */
if( lAcknowledgeTick != pdFALSE )
{
vPortTrace( "prvProcessEvents: Acking tick\r\n" );
SetEvent( pvTickAcknowledgeEvent );
}
if( lAcknowledgeInterrupt != pdFALSE ) if( pxThreadState->lWaitingInterruptAck == pdTRUE )
{ {
vPortTrace( "prvProcessEvents: Acking interrupt\r\n" ); pxThreadState->lWaitingInterruptAck = pdFALSE;
SetEvent( pvInterruptAcknowledgeEvent ); vPortTrace( "prvProcessEvents: Acking interrupt\r\n" );
SetEvent( pvInterruptAcknowledgeEvent );
}
}
} }
ReleaseMutex( pvInterruptEventMutex ); ReleaseMutex( pvInterruptEventMutex );
@ -496,23 +425,26 @@ void vPortEndScheduler( void )
void vPortGeneratePseudoInterrupt( unsigned long ulInterruptNumber ) void vPortGeneratePseudoInterrupt( unsigned long ulInterruptNumber )
{ {
xThreadState *pxThreadState;
if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) ) if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )
{ {
/* Yield interrupts are processed even when critical nesting is non-zero. */ /* Yield interrupts are processed even when critical nesting is non-zero. */
if( ( ulCriticalNesting == 0 ) || ( ulInterruptNumber == portINTERRUPT_YIELD ) ) if( ( ulCriticalNesting == 0 ) || ( ulInterruptNumber == portINTERRUPT_YIELD ) )
{ {
/* In case this task has just started running, reset the interrupt
acknowledge event as it might have been set due to the activities
of a thread that has already been executed and suspended. */
ResetEvent( pvInterruptAcknowledgeEvent );
WaitForSingleObject( pvInterruptEventMutex, INFINITE ); WaitForSingleObject( pvInterruptEventMutex, INFINITE );
ulPendingInterrupts |= ( 1 << ulInterruptNumber ); ulPendingInterrupts |= ( 1 << ulInterruptNumber );
/* The event handler needs to know to signal the interrupt acknowledge event
the next time this task runs. */
pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
pxThreadState->lWaitingInterruptAck = pdTRUE;
vPortTrace( "vPortGeneratePseudoInterrupt: Got interrupt mutex, about to signal interrupt event\r\n" ); vPortTrace( "vPortGeneratePseudoInterrupt: Got interrupt mutex, about to signal interrupt event\r\n" );
SetEvent( pvInterruptEvent ); SetEvent( pvInterruptEvent );
vPortTrace( "vPortGeneratePseudoInterrupt: About to release interrupt event mutex\r\n" ); vPortTrace( "vPortGeneratePseudoInterrupt: About to release interrupt event mutex\r\n" );
ReleaseMutex( pvInterruptEventMutex ); ReleaseMutex( pvInterruptEventMutex );
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for next interrupt input\r\n" ); vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt event mutex released, going to wait for interrupt ack\r\n" );
WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE ); WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );
vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt acknowledged, leaving vPortGeneratePseudoInterrupt()\r\n" ); vPortTrace( "vPortGeneratePseudoInterrupt: Interrupt acknowledged, leaving vPortGeneratePseudoInterrupt()\r\n" );
@ -547,6 +479,8 @@ void vPortEnterCritical( void )
void vPortExitCritical( void ) void vPortExitCritical( void )
{ {
xThreadState *pxThreadState;
if( ulCriticalNesting > portNO_CRITICAL_NESTING ) if( ulCriticalNesting > portNO_CRITICAL_NESTING )
{ {
ulCriticalNesting--; ulCriticalNesting--;
@ -560,16 +494,17 @@ void vPortExitCritical( void )
WaitForSingleObject( pvInterruptEventMutex, INFINITE ); WaitForSingleObject( pvInterruptEventMutex, INFINITE );
vPortTrace( "vPortExitCritical: Setting interrupt event\r\n" ); vPortTrace( "vPortExitCritical: Setting interrupt event\r\n" );
SetEvent( pvInterruptEvent ); SetEvent( pvInterruptEvent );
/* The event handler needs to know to signal the interrupt acknowledge event
the next time this task runs. */
pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );
pxThreadState->lWaitingInterruptAck = pdTRUE;
ReleaseMutex( pvInterruptEventMutex ); ReleaseMutex( pvInterruptEventMutex );
vPortTrace( "vPortExitCritical: Waiting interrupt ack\r\n" ); vPortTrace( "vPortExitCritical: Waiting interrupt ack\r\n" );
WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE ); WaitForSingleObject( pvInterruptAcknowledgeEvent, INFINITE );
vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" ); vPortTrace( "vPortExitCritical: Interrupt acknowledged, leaving critical section code\r\n" );
/* Just in case the Yield does not happen immediately. This
line could be dangerious if not all interrupts are being
processed. */
// while( ulPendingInterrupts != 0UL );
} }
} }
} }

Loading…
Cancel
Save