mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-21 22:11:57 -04:00
Updated Win32 port layer so that end of interrupt events are only sent to threads that are actually waiting for them.
This commit is contained in:
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,10 +204,7 @@ 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
|
/* 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
|
is created that will execute the task being created. The thread handles
|
||||||
the context switching itself. The xThreadState object is placed onto
|
the context switching itself. The xThreadState object is placed onto
|
||||||
|
@ -270,17 +213,11 @@ xParams *pxThreadParams = ( void * ) pvPortMalloc( sizeof( xParams ) );
|
||||||
other than holding this structure. */
|
other than holding this structure. */
|
||||||
pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );
|
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,28 +396,22 @@ 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( pxThreadState->lWaitingInterruptAck == pdTRUE )
|
||||||
if( lAcknowledgeTick != pdFALSE )
|
|
||||||
{
|
|
||||||
vPortTrace( "prvProcessEvents: Acking tick\r\n" );
|
|
||||||
SetEvent( pvTickAcknowledgeEvent );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( lAcknowledgeInterrupt != pdFALSE )
|
|
||||||
{
|
{
|
||||||
|
pxThreadState->lWaitingInterruptAck = pdFALSE;
|
||||||
vPortTrace( "prvProcessEvents: Acking interrupt\r\n" );
|
vPortTrace( "prvProcessEvents: Acking interrupt\r\n" );
|
||||||
SetEvent( pvInterruptAcknowledgeEvent );
|
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…
Reference in a new issue