]> git.sur5r.net Git - freertos/commitdiff
Work on Win32 port layer - removing the need to store the critical section nesting...
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Fri, 19 Nov 2010 22:37:02 +0000 (22:37 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Fri, 19 Nov 2010 22:37:02 +0000 (22:37 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1146 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Source/portable/MSVC-MingW/port.c

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