]> git.sur5r.net Git - freertos/blobdiff - Source/portable/MSVC-MingW/port.c
Replace waitable timer with sleep function in Win32 port layer.
[freertos] / Source / portable / MSVC-MingW / port.c
index dbd49597e875b4e94934e30b5163627c9fff538f..059a91fa933e1577aeed4432803ce6adeb904076 100644 (file)
 #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
@@ -137,16 +85,17 @@ the only thing it will ever hold.  The structure indirectly maps the task handle
 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
@@ -188,43 +137,20 @@ extern void *pxCurrentTCB;
 \r
 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )\r
 {\r
-void *pvTimer;\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
-       /* The timer is created as a one shot timer even though we want it to repeat\r
-       at a given frequency.  This is because Windows is not a real time environment,\r
-       and attempting to set a high frequency periodic timer will result in event\r
-       overruns.  Therefore the timer is just reset after each time the pseudo \r
-       interrupt handler has processed each tick event. */\r
-       pvTimer = CreateWaitableTimer( NULL, TRUE, NULL );\r
-       \r
-       liDueTime.QuadPart = ( long long ) portTICK_RATE_MS * ll_ms_In_100ns_units;\r
-\r
-       /* Block on the timer itself and the event mutex that grants access to the \r
-       interrupt variables. */\r
-       pvObjectList[ 0 ] = pvInterruptEventMutex;\r
-       pvObjectList[ 1 ] = pvTimer;\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
-               vPortTrace( "prvSimulatedPeripheralTimer: Tick acked, setting new tick timer\r\n" );\r
-               SetWaitableTimer( pvTimer, &liDueTime, 0, NULL, NULL, TRUE );\r
+               vPortTrace( "prvSimulatedPeripheralTimer: Tick acked, re-Sleeping()\r\n" );\r
 \r
                /* Wait until the timer expires and we can access the pseudo interrupt \r
                variables. */\r
-               //WaitForMultipleObjects( ( sizeof( pvObjectList ) / sizeof( void * ) ), pvObjectList, TRUE, INFINITE );\r
-               WaitForSingleObject( pvTimer, INFINITE );\r
+               Sleep( portTICK_RATE_MS );\r
+\r
                vPortTrace( "prvSimulatedPeripheralTimer: Timer signalled, waiting interrupt event mutex\r\n" );\r
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
                vPortTrace( "prvSimulatedPeripheralTimer: Got interrupt event mutex\r\n" );\r
@@ -258,29 +184,20 @@ extern volatile unsigned long ulTicks;
 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
@@ -347,11 +264,11 @@ xThreadState *pxThreadState;
 \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
@@ -372,8 +289,6 @@ char cTraceBuffer[ 256 ];
                //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
@@ -392,8 +307,6 @@ char cTraceBuffer[ 256 ];
 \r
                                                /* Clear the interrupt pending bit. */\r
                                                ulPendingInterrupts &= ~( 1UL << portINTERRUPT_YIELD );\r
-\r
-                                               lAcknowledgeInterrupt = pdTRUE;\r
                                                break;\r
 \r
                                        case portINTERRUPT_TICK:\r
@@ -415,7 +328,8 @@ char cTraceBuffer[ 256 ];
                                                        }\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
@@ -435,7 +349,8 @@ char cTraceBuffer[ 256 ];
                                                        /* 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
@@ -461,27 +376,21 @@ char cTraceBuffer[ 256 ];
                        {\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
@@ -496,23 +405,26 @@ void vPortEndScheduler( void )
 \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
@@ -547,6 +459,8 @@ void vPortEnterCritical( void )
 \r
 void vPortExitCritical( void )\r
 {\r
+xThreadState *pxThreadState;\r
+\r
        if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
        {\r
                ulCriticalNesting--;\r
@@ -560,16 +474,17 @@ void vPortExitCritical( void )
                                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