]> git.sur5r.net Git - freertos/blobdiff - Source/portable/MSVC-MingW/port.c
WIN32 simulator port: Allow the configTICK_RATE_HZ to be increased without making...
[freertos] / Source / portable / MSVC-MingW / port.c
index e880a0977808f19226e7b5865f3cef2f555ac66e..c50383f9976b9dd6f1bc54d93851a550630ce29a 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-    FreeRTOS V6.1.0 - Copyright (C) 2010 Real Time Engineers Ltd.\r
+    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.\r
 \r
     ***************************************************************************\r
     *                                                                         *\r
 #include "task.h"\r
 #include <stdio.h>\r
 \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
 #define portMAX_INTERRUPTS                             ( ( unsigned long ) sizeof( unsigned long ) * 8UL ) /* The number of bits in an unsigned long. */\r
 #define portNO_CRITICAL_NESTING                ( ( unsigned long ) 0 )\r
 \r
@@ -75,7 +71,15 @@ static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter );
  * Process all the simulated interrupts - each represented by a bit in \r
  * ulPendingInterrupts variable.\r
  */\r
-static void prvProcessPseudoInterrupts( void );\r
+static void prvProcessSimulatedInterrupts( void );\r
+\r
+/*\r
+ * Interrupt handlers used by the kernel itself.  These are executed from the\r
+ * simulated interrupt handler thread.\r
+ */\r
+static unsigned long prvProcessDeleteThreadInterrupt( void );\r
+static unsigned long prvProcessYieldInterrupt( void );\r
+static unsigned long prvProcessTickInterrupt( void );\r
 \r
 /*-----------------------------------------------------------*/\r
 \r
@@ -86,47 +90,37 @@ the only thing it will ever hold.  The structure indirectly maps the task handle
 to a thread handle. */\r
 typedef struct\r
 {\r
-       /* Set to true if the task run by the thread yielded control to the pseudo\r
-       interrupt handler manually - either by yielding or when exiting a critical\r
-       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
+       void *pvThread;\r
+\r
 } xThreadState;\r
 \r
-/* Pseudo interrupts waiting to be processed.  This is a bit mask where each\r
+/* Simulated 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
 static volatile unsigned long ulPendingInterrupts = 0UL;\r
 \r
-/* An event used to inform the pseudo interrupt processing thread (a high \r
+/* An event used to inform the simulated interrupt processing thread (a high \r
 priority thread that simulated interrupt processing) that an interrupt is\r
 pending. */\r
 static void *pvInterruptEvent = NULL;\r
 \r
-/* Mutex used to protect all the pseudo interrupt variables that are accessed \r
+/* Mutex used to protect all the simulated interrupt variables that are accessed \r
 by multiple threads. */\r
 static void *pvInterruptEventMutex = NULL;\r
 \r
-/* Events used to manage sequencing. */\r
-static void *pvTickAcknowledgeEvent = NULL, *pvInterruptAcknowledgeEvent = NULL;\r
-\r
 /* The critical nesting count for the currently executing task.  This is \r
 initialised to a non-zero value so interrupts do not become enabled during \r
 the initialisation phase.  As each task has its own critical nesting value \r
 ulCriticalNesting will get set to zero when the first task runs.  This \r
 initialisation is probably not critical in this simulated environment as the\r
-pseudo interrupt handlers do not get created until the FreeRTOS scheduler is \r
+simulated interrupt handlers do not get created until the FreeRTOS scheduler is \r
 started anyway. */\r
 static unsigned long ulCriticalNesting = 9999UL;\r
 \r
 /* Handlers for all the simulated software interrupts.  The first two positions\r
 are used for the Yield and Tick interrupts so are handled slightly differently,\r
 all the other interrupts can be user defined. */\r
-static void (*vIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };\r
+static unsigned long (*ulIsrHandler[ portMAX_INTERRUPTS ])( void ) = { 0 };\r
 \r
 /* Pointer to the TCB of the currently executing task. */\r
 extern void *pxCurrentTCB;\r
@@ -135,47 +129,47 @@ extern void *pxCurrentTCB;
 \r
 static DWORD WINAPI prvSimulatedPeripheralTimer( LPVOID lpParameter )\r
 {\r
+portTickType xMinimumWindowsBlockTime = ( portTickType ) 20;\r
+\r
        /* Just to prevent compiler warnings. */\r
        ( void ) lpParameter;\r
 \r
        for(;;)\r
        {\r
-               vPortTrace( "prvSimulatedPeripheralTimer: Tick acked, re-Sleeping()\r\n" );\r
-\r
-               /* Wait until the timer expires and we can access the pseudo interrupt \r
+               /* Wait until the timer expires and we can access the simulated interrupt \r
                variables.  *NOTE* this is not a 'real time' way of generating tick \r
                events as the next wake time should be relative to the previous wake \r
                time, not the time that Sleep() is called.  It is done this way to \r
                prevent overruns in this very non real time simulated/emulated \r
                environment. */\r
-               Sleep( portTICK_RATE_MS );\r
-\r
-               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
+               if( portTICK_RATE_MS < xMinimumWindowsBlockTime )\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
+                       Sleep( xMinimumWindowsBlockTime );\r
                }\r
                else\r
                {\r
-                       ReleaseMutex( pvInterruptEventMutex );\r
+                       Sleep( portTICK_RATE_MS );\r
                }\r
+       \r
+               WaitForSingleObject( pvInterruptEventMutex, INFINITE );\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
+               SetEvent( pvInterruptEvent );\r
+\r
+               /* Give back the mutex so the simulated interrupt handler unblocks \r
+               and can access the interrupt handler variables. */\r
+               ReleaseMutex( pvInterruptEventMutex );\r
        }\r
+\r
+       #ifdef __GNUC__\r
+               /* Should never reach here - MingW complains if you leave this line out,\r
+               MSVC complains if you put it in. */\r
+               return 0;\r
+       #endif\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
@@ -192,10 +186,9 @@ xThreadState *pxThreadState = NULL;
        pxThreadState = ( xThreadState * ) ( pxTopOfStack - sizeof( xThreadState ) );\r
 \r
        /* Create the thread itself. */\r
-       pxThreadState->pvThread = ( void * ) CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );\r
+       pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );\r
+       SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );\r
        SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );\r
-       pxThreadState->ulCriticalNesting = portNO_CRITICAL_NESTING;\r
-       pxThreadState->lWaitingInterruptAck = pdFALSE;\r
        SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );\r
        \r
        return ( portSTACK_TYPE * ) pxThreadState;\r
@@ -208,22 +201,24 @@ void *pvHandle;
 long lSuccess = pdPASS;\r
 xThreadState *pxThreadState;\r
 \r
+       /* Install the interrupt handlers used by the scheduler itself. */\r
+       vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );\r
+       vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );\r
+       vPortSetInterruptHandler( portINTERRUPT_DELETE_THREAD, prvProcessDeleteThreadInterrupt );\r
+\r
        /* Create the events and mutexes that are used to synchronise all the\r
        threads. */\r
        pvInterruptEventMutex = CreateMutex( NULL, FALSE, NULL );\r
        pvInterruptEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
-       pvTickAcknowledgeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
-       pvInterruptAcknowledgeEvent = CreateEvent( NULL, FALSE, FALSE, NULL );\r
 \r
-       if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) || ( pvTickAcknowledgeEvent == NULL ) || ( pvInterruptAcknowledgeEvent == NULL ) )\r
+       if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )\r
        {\r
                lSuccess = pdFAIL;\r
        }\r
 \r
        /* Set the priority of this thread such that it is above the priority of \r
        the threads that run tasks.  This higher priority is required to ensure\r
-       pseudo interrupts take priority over tasks. */\r
-       SetPriorityClass( GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS );\r
+       simulated interrupts take priority over tasks. */\r
        pvHandle = GetCurrentThread();\r
        if( pvHandle == NULL )\r
        {\r
@@ -232,22 +227,26 @@ xThreadState *pxThreadState;
        \r
        if( lSuccess == pdPASS )\r
        {\r
-               if( SetThreadPriority( pvHandle, THREAD_PRIORITY_HIGHEST ) == 0 )\r
+               if( SetThreadPriority( pvHandle, THREAD_PRIORITY_NORMAL ) == 0 )\r
                {\r
                        lSuccess = pdFAIL;\r
                }\r
                SetThreadPriorityBoost( pvHandle, TRUE );\r
+               SetThreadAffinityMask( pvHandle, 0x01 );\r
        }\r
 \r
        if( lSuccess == pdPASS )\r
        {\r
                /* Start the thread that simulates the timer peripheral to generate\r
-               tick interrupts. */\r
+               tick interrupts.  The priority is set below that of the simulated \r
+               interrupt handler so the interrupt event mutex is used for the\r
+               handshake / overrun protection. */\r
                pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, 0, NULL );\r
                if( pvHandle != NULL )\r
                {\r
-                       SetThreadPriority( pvHandle, THREAD_PRIORITY_HIGHEST );\r
+                       SetThreadPriority( pvHandle, THREAD_PRIORITY_BELOW_NORMAL );\r
                        SetThreadPriorityBoost( pvHandle, TRUE );\r
+                       SetThreadAffinityMask( pvHandle, 0x01 );\r
                }\r
                \r
                /* Start the highest priority task by obtaining its associated thread \r
@@ -255,184 +254,127 @@ xThreadState *pxThreadState;
                pxThreadState = ( xThreadState * ) *( ( unsigned long * ) pxCurrentTCB );\r
                ulCriticalNesting = portNO_CRITICAL_NESTING;\r
 \r
-               vPortTrace( "Created system threads, starting task" );\r
-\r
                /* Bump up the priority of the thread that is going to run, in the\r
                hope that this will asist in getting the Windows thread scheduler to\r
                behave as an embedded engineer might expect. */\r
-               SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );\r
                ResumeThread( pxThreadState->pvThread );\r
 \r
-               /* Handle all pseudo interrupts - including yield requests and \r
+               /* Handle all simulated interrupts - including yield requests and \r
                simulated ticks. */\r
-               prvProcessPseudoInterrupts();\r
+               prvProcessSimulatedInterrupts();\r
        }       \r
        \r
-       /* Would not expect to return from prvProcessPseudoInterrupts(), so should \r
+       /* Would not expect to return from prvProcessSimulatedInterrupts(), so should \r
        not get here. */\r
        return 0;\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-static void prvProcessPseudoInterrupts( void )\r
+static unsigned long prvProcessDeleteThreadInterrupt( void )\r
+{\r
+       return pdTRUE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static unsigned long prvProcessYieldInterrupt( void )\r
+{\r
+       return pdTRUE;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static unsigned long prvProcessTickInterrupt( void )\r
+{\r
+unsigned long ulSwitchRequired;\r
+\r
+       /* Process the tick itself. */\r
+       vTaskIncrementTick();\r
+       #if( configUSE_PREEMPTION != 0 )\r
+       {\r
+               /* A context switch is only automatically performed from the tick\r
+               interrupt if the pre-emptive scheduler is being used. */\r
+               ulSwitchRequired = pdTRUE;\r
+       }\r
+       #else\r
+       {\r
+               ulSwitchRequired = pdFALSE;\r
+       }\r
+       #endif\r
+\r
+       return ulSwitchRequired;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvProcessSimulatedInterrupts( void )\r
 {\r
-long lSwitchRequired;\r
+unsigned long ulSwitchRequired, i;\r
 xThreadState *pxThreadState;\r
 void *pvObjectList[ 2 ];\r
-unsigned long i;\r
-//char cTraceBuffer[ 256 ];\r
-\r
-       vPortTrace( "Entering prvProcessPseudoInterrupts\r\n" );\r
 \r
-       /* Going to block on the mutex that ensured exclusive access to the pseudo \r
-       interrupt objects, and the event that signals that a pseudo interrupt\r
+       /* Going to block on the mutex that ensured exclusive access to the simulated \r
+       interrupt objects, and the event that signals that a simulated interrupt\r
        should be processed. */\r
        pvObjectList[ 0 ] = pvInterruptEventMutex;\r
        pvObjectList[ 1 ] = pvInterruptEvent;\r
 \r
        for(;;)\r
        {\r
-               vPortTrace( "prvProcessPseudoInterrupts: Waiting for next interrupt event\r\n" );\r
                WaitForMultipleObjects( sizeof( pvObjectList ) / sizeof( void * ), pvObjectList, TRUE, INFINITE );\r
-               vPortTrace( "prvProcessPseudoInterrupts: Got interrupt event and mutex\r\n" );\r
 \r
-               /* Used to indicate whether the pseudo interrupt processing has\r
+               /* Used to indicate whether the simulated interrupt processing has\r
                necessitated a context switch to another task/thread. */\r
-               lSwitchRequired = pdFALSE;\r
+               ulSwitchRequired = 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
                for( i = 0; i < portMAX_INTERRUPTS; i++ )\r
                {\r
-                       /* Is the pseudo interrupt pending? */\r
+                       /* Is the simulated interrupt pending? */\r
                        if( ulPendingInterrupts & ( 1UL << i ) )\r
                        {\r
-                               switch( i )\r
+                               /* Is a handler installed? */\r
+                               if( ulIsrHandler[ i ] != NULL )\r
                                {\r
-                                       case portINTERRUPT_YIELD:\r
-\r
-                                               vPortTrace( "prvProcessPseudoInterrupts: Processing Yield\r\n" );\r
-                                               lSwitchRequired = pdTRUE;\r
-\r
-                                               /* Clear the interrupt pending bit. */\r
-                                               ulPendingInterrupts &= ~( 1UL << portINTERRUPT_YIELD );\r
-                                               break;\r
-\r
-                                       case portINTERRUPT_TICK:\r
-                                       \r
-                                               /* Tick interrupts should only be processed if the \r
-                                               critical nesting count is zero.  The critical nesting \r
-                                               count represents the interrupt mask on real target \r
-                                               hardware.  The thread that genereates ticks will not\r
-                                               actually ask for the tick to be processed unless the\r
-                                               critical nesting count is zero anyway, but it is \r
-                                               possible that a tick is pending when a yield is \r
-                                               performed (depending on if the simulation/emulation is\r
-                                               set up to process yields while within a critical \r
-                                               section. */\r
-                                               vPortTrace( "prvProcessPseudoInterrupts: Processing tick event\r\n" );\r
-                                               if( ulCriticalNesting == 0UL )\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
-                                                       \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
-                                               break;\r
-\r
-                                       default:\r
-\r
-                                               if( ulCriticalNesting == 0UL )\r
-                                               {\r
-                                                       /* Is a handler installed? */\r
-                                                       if( vIsrHandler[ i ] != NULL )\r
-                                                       {\r
-                                                               lSwitchRequired = pdTRUE;\r
-\r
-                                                               /* Run the actual handler. */\r
-                                                               vIsrHandler[ i ]();\r
-\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
-                                               }\r
-                                               break;\r
+                                       /* Run the actual handler. */\r
+                                       if( ulIsrHandler[ i ]() != pdFALSE )\r
+                                       {\r
+                                               ulSwitchRequired |= ( 1 << i );\r
+                                       }\r
                                }\r
+\r
+                               /* Clear the interrupt pending bit. */\r
+                               ulPendingInterrupts &= ~( 1UL << i );\r
                        }\r
                }\r
 \r
-               if( lSwitchRequired != pdFALSE )\r
+               if( ulSwitchRequired != pdFALSE )\r
                {\r
                        void *pvOldCurrentTCB;\r
 \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
+\r
                        /* If the task selected to enter the running state is not the task\r
                        that is already in the running state. */\r
                        if( pvOldCurrentTCB != pxCurrentTCB )\r
                        {\r
                                /* Suspend the old thread. */\r
-                               SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );\r
-                               SuspendThread( pxThreadState->pvThread );\r
+                               pxThreadState = ( xThreadState *) *( ( unsigned long * ) pvOldCurrentTCB );\r
 \r
-                               //sprintf( cTraceBuffer, "Event processor: suspending %s, resuming %s\r\n", ((xTCB*)pvOldCurrentTCB)->pcTaskName, ((xTCB*)pxCurrentTCB)->pcTaskName );\r
-                               //vPortTrace( cTraceBuffer );\r
+                               if( ( ulSwitchRequired & ( 1 << portINTERRUPT_DELETE_THREAD ) ) != pdFALSE )\r
+                               {\r
+                                       TerminateThread( pxThreadState->pvThread, 0 );\r
+                               }\r
+                               else\r
+                               {\r
+                                       SuspendThread( pxThreadState->pvThread );\r
+                               }                                                       \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
-                               SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_ABOVE_NORMAL );\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
-                               pxThreadState->lWaitingInterruptAck = pdFALSE;\r
-                               vPortTrace( "prvProcessPseudoInterrupts: Acking interrupt even though a yield has not been performed.\r\n" );\r
-                               SetEvent( pvInterruptAcknowledgeEvent );\r
                        }\r
                }\r
 \r
@@ -441,12 +383,38 @@ unsigned long i;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
+void vPortDeleteThread( void *pvTaskToDelete )\r
+{\r
+xThreadState *pxThreadState;\r
+\r
+       if( pvTaskToDelete == pxCurrentTCB )\r
+       {\r
+               /* The task is deleting itself, and so the thread that is running now\r
+               is also to be deleted.  This has to be deferred until this thread is\r
+               no longer running, so its done in the simulated interrupt handler thread. */\r
+               vPortGenerateSimulatedInterrupt( portINTERRUPT_DELETE_THREAD );\r
+       }\r
+       else\r
+       {\r
+               WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
+\r
+               /* Find the handle of the thread being deleted. */\r
+               pxThreadState = ( xThreadState * ) ( *( unsigned long *) pvTaskToDelete );\r
+               TerminateThread( pxThreadState->pvThread, 0 );\r
+\r
+               ReleaseMutex( pvInterruptEventMutex );\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
 void vPortEndScheduler( void )\r
 {\r
+       /* This function IS NOT TESTED! */\r
+       TerminateProcess( GetCurrentProcess(), 0 );\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-void vPortGeneratePseudoInterrupt( unsigned long ulInterruptNumber )\r
+void vPortGenerateSimulatedInterrupt( unsigned long ulInterruptNumber )\r
 {\r
 xThreadState *pxThreadState;\r
 \r
@@ -456,53 +424,35 @@ xThreadState *pxThreadState;
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
                ulPendingInterrupts |= ( 1 << ulInterruptNumber );\r
 \r
-               if( ulCriticalNesting == 0 ) //|| ( ulInterruptNumber == portINTERRUPT_YIELD ) )\r
+               /* The simulated 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
                        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
-\r
-                       /* The interrupt ack event should not be signaled yet - if it is then there\r
-                       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
-                       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
-                       ReleaseMutex( pvInterruptEventMutex );\r
+                       SetEvent( pvInterruptEvent );                   \r
                }\r
+\r
+               ReleaseMutex( pvInterruptEventMutex );\r
        }\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-void vPortSetInterruptHandler( unsigned long ulInterruptNumber, void (*pvHandler)( void ) )\r
+void vPortSetInterruptHandler( unsigned long ulInterruptNumber, unsigned long (*pvHandler)( void ) )\r
 {\r
        if( ulInterruptNumber < portMAX_INTERRUPTS )\r
        {\r
                if( pvInterruptEventMutex != NULL )\r
                {\r
                        WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
-                       vIsrHandler[ ulInterruptNumber ] = pvHandler;\r
+                       ulIsrHandler[ ulInterruptNumber ] = pvHandler;\r
                        ReleaseMutex( pvInterruptEventMutex );\r
                }\r
                else\r
                {\r
-                       vIsrHandler[ ulInterruptNumber ] = pvHandler;\r
+                       ulIsrHandler[ ulInterruptNumber ] = pvHandler;\r
                }\r
        }\r
 }\r
@@ -512,10 +462,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 (simulated) interrupts. */\r
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
-//             SuspendThread( pvSimulatedTimerThread );\r
                ulCriticalNesting++;\r
-               ReleaseMutex( pvInterruptEventMutex );\r
        }\r
        else\r
        {\r
@@ -527,54 +477,32 @@ 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
-                       (pseudo) disabled? */\r
+                       (simulated) disabled? */\r
                        if( ulPendingInterrupts != 0UL )\r
                        {\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
-                               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
+                               /* Mutex will be released now, so does not require releasing\r
+                               on function exit. */\r
+                               lMutexNeedsReleasing = pdFALSE;\r
                                ReleaseMutex( pvInterruptEventMutex );\r
                        }\r
                }\r
@@ -585,4 +513,11 @@ xThreadState *pxThreadState;
                        ulCriticalNesting--;\r
                }\r
        }\r
+\r
+       if( lMutexNeedsReleasing == pdTRUE )\r
+       {\r
+               ReleaseMutex( pvInterruptEventMutex );\r
+       }\r
 }\r
+/*-----------------------------------------------------------*/\r
+\r