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