]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Source/portable/MSVC-MingW/port.c
Update version number in preparation for maintenance release.
[freertos] / FreeRTOS / Source / portable / MSVC-MingW / port.c
index 05e43699d61a738ddecec0d8ab3d351b6375ec9f..54292288b60ba521e07bb7d5c5c63172c2b725d8 100644 (file)
@@ -1,60 +1,64 @@
 /*\r
-    FreeRTOS V8.1.0 - Copyright (C) 2014 Real Time Engineers Ltd.\r
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.\r
     All rights reserved\r
 \r
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
 \r
-    ***************************************************************************\r
-     *                                                                       *\r
-     *    FreeRTOS provides completely free yet professionally developed,    *\r
-     *    robust, strictly quality controlled, supported, and cross          *\r
-     *    platform software that has become a de facto standard.             *\r
-     *                                                                       *\r
-     *    Help yourself get started quickly and support the FreeRTOS         *\r
-     *    project by purchasing a FreeRTOS tutorial book, reference          *\r
-     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
-     *                                                                       *\r
-     *    Thank you!                                                         *\r
-     *                                                                       *\r
-    ***************************************************************************\r
-\r
     This file is part of the FreeRTOS distribution.\r
 \r
     FreeRTOS is free software; you can redistribute it and/or modify it under\r
     the terms of the GNU General Public License (version 2) as published by the\r
-    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
+    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.\r
 \r
+    ***************************************************************************\r
     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
     >>!   obliged to provide the source code for proprietary components     !<<\r
     >>!   outside of the FreeRTOS kernel.                                   !<<\r
+    ***************************************************************************\r
 \r
     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
-    FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
+    FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
     link: http://www.freertos.org/a00114.html\r
 \r
-    1 tab == 4 spaces!\r
-\r
     ***************************************************************************\r
      *                                                                       *\r
-     *    Having a problem?  Start by reading the FAQ "My application does   *\r
-     *    not run, what could be wrong?"                                     *\r
+     *    FreeRTOS provides completely free yet professionally developed,    *\r
+     *    robust, strictly quality controlled, supported, and cross          *\r
+     *    platform software that is more than just the market leader, it     *\r
+     *    is the industry's de facto standard.                               *\r
      *                                                                       *\r
-     *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
+     *    Help yourself get started quickly while simultaneously helping     *\r
+     *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
+     *    tutorial book, reference manual, or both:                          *\r
+     *    http://www.FreeRTOS.org/Documentation                              *\r
      *                                                                       *\r
     ***************************************************************************\r
 \r
-    http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
-    license and Real Time Engineers Ltd. contact details.\r
+    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
+    the FAQ page "My application does not run, what could be wrong?".  Have you\r
+    defined configASSERT()?\r
+\r
+    http://www.FreeRTOS.org/support - In return for receiving this top quality\r
+    embedded software for free we request you assist our global community by\r
+    participating in the support forum.\r
+\r
+    http://www.FreeRTOS.org/training - Investing in training allows your team to\r
+    be as productive as possible as early as possible.  Now you can receive\r
+    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
+    Ltd, and the world's leading authority on the world's leading RTOS.\r
 \r
     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
 \r
-    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
-    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
-    licenses offer ticketed support, indemnification and middleware.\r
+    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
+    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
+\r
+    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
+    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
+    licenses offer ticketed support, indemnification and commercial middleware.\r
 \r
     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
     engineered and independently SIL3 certified version for use in safety and\r
     1 tab == 4 spaces!\r
 */\r
 \r
+/* Standard includes. */\r
+#include <stdio.h>\r
+\r
 /* Scheduler includes. */\r
 #include "FreeRTOS.h"\r
 #include "task.h"\r
-#include <stdio.h>\r
 \r
 #ifdef __GNUC__\r
        #include "mmsystem.h"\r
 #define portMAX_INTERRUPTS                             ( ( uint32_t ) sizeof( uint32_t ) * 8UL ) /* The number of bits in an uint32_t. */\r
 #define portNO_CRITICAL_NESTING                ( ( uint32_t ) 0 )\r
 \r
+/* The priorities at which the various components of the simulation execute. */\r
+#define portDELETE_SELF_THREAD_PRIORITY                         THREAD_PRIORITY_TIME_CRITICAL /* Must be highest. */\r
+#define portSIMULATED_INTERRUPTS_THREAD_PRIORITY THREAD_PRIORITY_TIME_CRITICAL\r
+#define portSIMULATED_TIMER_THREAD_PRIORITY             THREAD_PRIORITY_HIGHEST\r
+#define portTASK_THREAD_PRIORITY                                THREAD_PRIORITY_ABOVE_NORMAL\r
+\r
 /*\r
  * Created as a high priority thread, this function uses a timer to simulate\r
  * a tick interrupt being generated on an embedded target.  In this Windows\r
@@ -176,7 +188,7 @@ TIMECAPS xTimeCaps;
        /* Just to prevent compiler warnings. */\r
        ( void ) lpParameter;\r
 \r
-       for(;;)\r
+       for( ;; )\r
        {\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
@@ -241,6 +253,7 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
 {\r
 xThreadState *pxThreadState = NULL;\r
 int8_t *pcTopOfStack = ( int8_t * ) pxTopOfStack;\r
+const SIZE_T xStackSize = 1024; /* Set the size to a small number which will get rounded up to the minimum possible. */\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
@@ -251,11 +264,11 @@ int8_t *pcTopOfStack = ( int8_t * ) pxTopOfStack;
        pxThreadState = ( xThreadState * ) ( pcTopOfStack - sizeof( xThreadState ) );\r
 \r
        /* Create the thread itself. */\r
-       pxThreadState->pvThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED, NULL );\r
-       configASSERT( pxThreadState->pvThread );\r
+       pxThreadState->pvThread = CreateThread( NULL, xStackSize, ( LPTHREAD_START_ROUTINE ) pxCode, pvParameters, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, NULL );\r
+       configASSERT( pxThreadState->pvThread ); /* See comment where TerminateThread() is called. */\r
        SetThreadAffinityMask( pxThreadState->pvThread, 0x01 );\r
        SetThreadPriorityBoost( pxThreadState->pvThread, TRUE );\r
-       SetThreadPriority( pxThreadState->pvThread, THREAD_PRIORITY_IDLE );\r
+       SetThreadPriority( pxThreadState->pvThread, portTASK_THREAD_PRIORITY );\r
 \r
        return ( StackType_t * ) pxThreadState;\r
 }\r
@@ -263,36 +276,58 @@ int8_t *pcTopOfStack = ( int8_t * ) pxTopOfStack;
 \r
 BaseType_t xPortStartScheduler( void )\r
 {\r
-void *pvHandle;\r
-int32_t 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
-\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
+void *pvHandle = NULL;\r
+int32_t lSuccess;\r
+xThreadState *pxThreadState = NULL;\r
+SYSTEM_INFO xSystemInfo;\r
 \r
-       if( ( pvInterruptEventMutex == NULL ) || ( pvInterruptEvent == NULL ) )\r
+       /* This port runs windows threads with extremely high priority.  All the\r
+       threads execute on the same core - to prevent locking up the host only start\r
+       if the host has multiple cores. */\r
+       GetSystemInfo( &xSystemInfo );\r
+       if( xSystemInfo.dwNumberOfProcessors <= 1 )\r
        {\r
+               printf( "This version of the FreeRTOS Windows port can only be used on multi-core hosts.\r\n" );\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
-       simulated interrupts take priority over tasks. */\r
-       pvHandle = GetCurrentThread();\r
-       if( pvHandle == NULL )\r
+       else\r
        {\r
-               lSuccess = pdFAIL;\r
+               lSuccess = pdPASS;\r
+\r
+               /* The highest priority class is used to [try to] prevent other Windows\r
+               activity interfering with FreeRTOS timing too much. */\r
+               if( SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS ) == 0 )\r
+               {\r
+                       printf( "SetPriorityClass() failed\r\n" );\r
+               }\r
+\r
+               /* Install the interrupt handlers used by the scheduler itself. */\r
+               vPortSetInterruptHandler( portINTERRUPT_YIELD, prvProcessYieldInterrupt );\r
+               vPortSetInterruptHandler( portINTERRUPT_TICK, prvProcessTickInterrupt );\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
+\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
+               simulated interrupts take priority over tasks. */\r
+               pvHandle = GetCurrentThread();\r
+               if( pvHandle == NULL )\r
+               {\r
+                       lSuccess = pdFAIL;\r
+               }\r
        }\r
 \r
        if( lSuccess == pdPASS )\r
        {\r
-               if( SetThreadPriority( pvHandle, THREAD_PRIORITY_NORMAL ) == 0 )\r
+               if( SetThreadPriority( pvHandle, portSIMULATED_INTERRUPTS_THREAD_PRIORITY ) == 0 )\r
                {\r
                        lSuccess = pdFAIL;\r
                }\r
@@ -306,17 +341,18 @@ xThreadState *pxThreadState;
                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
+               pvHandle = CreateThread( NULL, 0, prvSimulatedPeripheralTimer, NULL, CREATE_SUSPENDED, NULL );\r
                if( pvHandle != NULL )\r
                {\r
-                       SetThreadPriority( pvHandle, THREAD_PRIORITY_BELOW_NORMAL );\r
+                       SetThreadPriority( pvHandle, portSIMULATED_TIMER_THREAD_PRIORITY );\r
                        SetThreadPriorityBoost( pvHandle, TRUE );\r
                        SetThreadAffinityMask( pvHandle, 0x01 );\r
+                       ResumeThread( pvHandle );\r
                }\r
 \r
                /* Start the highest priority task by obtaining its associated thread\r
                state structure, in which is stored the thread handle. */\r
-               pxThreadState = ( xThreadState * ) *( ( uint32_t * ) pxCurrentTCB );\r
+               pxThreadState = ( xThreadState * ) *( ( size_t * ) pxCurrentTCB );\r
                ulCriticalNesting = portNO_CRITICAL_NESTING;\r
 \r
                /* Bump up the priority of the thread that is going to run, in the\r
@@ -358,6 +394,7 @@ static void prvProcessSimulatedInterrupts( void )
 uint32_t ulSwitchRequired, i;\r
 xThreadState *pxThreadState;\r
 void *pvObjectList[ 2 ];\r
+CONTEXT xContext;\r
 \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
@@ -416,12 +453,19 @@ void *pvObjectList[ 2 ];
                        if( pvOldCurrentTCB != pxCurrentTCB )\r
                        {\r
                                /* Suspend the old thread. */\r
-                               pxThreadState = ( xThreadState *) *( ( uint32_t * ) pvOldCurrentTCB );\r
+                               pxThreadState = ( xThreadState *) *( ( size_t * ) pvOldCurrentTCB );\r
                                SuspendThread( pxThreadState->pvThread );\r
 \r
+                               /* Ensure the thread is actually suspended by performing a\r
+                               synchronous operation that can only complete when the thread is\r
+                               actually suspended.  The below code asks for dummy register\r
+                               data. */\r
+                               xContext.ContextFlags = CONTEXT_INTEGER;\r
+                               ( void ) GetThreadContext( pxThreadState->pvThread, &xContext );\r
+\r
                                /* Obtain the state of the task now selected to enter the\r
                                Running state. */\r
-                               pxThreadState = ( xThreadState * ) ( *( uint32_t *) pxCurrentTCB );\r
+                               pxThreadState = ( xThreadState * ) ( *( size_t *) pxCurrentTCB );\r
                                ResumeThread( pxThreadState->pvThread );\r
                        }\r
                }\r
@@ -440,7 +484,7 @@ uint32_t ulErrorCode;
        ( void ) ulErrorCode;\r
 \r
        /* Find the handle of the thread being deleted. */\r
-       pxThreadState = ( xThreadState * ) ( *( uint32_t *) pvTaskToDelete );\r
+       pxThreadState = ( xThreadState * ) ( *( size_t *) pvTaskToDelete );\r
 \r
        /* Check that the thread is still valid, it might have been closed by\r
        vPortCloseRunningThread() - which will be the case if the task associated\r
@@ -450,6 +494,10 @@ uint32_t ulErrorCode;
        {\r
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
 \r
+               /* !!! This is not a nice way to terminate a thread, and will eventually\r
+               result in resources being depleted if tasks frequently delete other\r
+               tasks (rather than deleting themselves) as the task stacks will not be\r
+               freed. */\r
                ulErrorCode = TerminateThread( pxThreadState->pvThread, 0 );\r
                configASSERT( ulErrorCode );\r
 \r
@@ -471,14 +519,14 @@ uint32_t ulErrorCode;
        ( void ) ulErrorCode;\r
 \r
        /* Find the handle of the thread being deleted. */\r
-       pxThreadState = ( xThreadState * ) ( *( uint32_t *) pvTaskToDelete );\r
+       pxThreadState = ( xThreadState * ) ( *( size_t *) pvTaskToDelete );\r
        pvThread = pxThreadState->pvThread;\r
 \r
        /* Raise the Windows priority of the thread to ensure the FreeRTOS scheduler\r
        does not run and swap it out before it is closed.  If that were to happen\r
        the thread would never run again and effectively be a thread handle and\r
        memory leak. */\r
-       SetThreadPriority( pvThread, THREAD_PRIORITY_ABOVE_NORMAL );\r
+       SetThreadPriority( pvThread, portDELETE_SELF_THREAD_PRIORITY );\r
 \r
        /* This function will not return, therefore a yield is set as pending to\r
        ensure a context switch occurs away from this thread on the next tick. */\r
@@ -492,6 +540,10 @@ uint32_t ulErrorCode;
        ulErrorCode = CloseHandle( pvThread );\r
        configASSERT( ulErrorCode );\r
 \r
+       /* This is called from a critical section, which must be exited before the\r
+       thread stops. */\r
+       taskEXIT_CRITICAL();\r
+\r
        ExitThread( 0 );\r
 }\r
 /*-----------------------------------------------------------*/\r
@@ -509,13 +561,15 @@ void vPortGenerateSimulatedInterrupt( uint32_t ulInterruptNumber )
 \r
        if( ( ulInterruptNumber < portMAX_INTERRUPTS ) && ( pvInterruptEventMutex != NULL ) )\r
        {\r
-               /* Yield interrupts are processed even when critical nesting is non-zero. */\r
+               /* Yield interrupts are processed even when critical nesting is\r
+               non-zero. */\r
                WaitForSingleObject( pvInterruptEventMutex, INFINITE );\r
                ulPendingInterrupts |= ( 1 << ulInterruptNumber );\r
 \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
+               /* The simulated interrupt is now held pending, but don't actually\r
+               process it yet if this call is within a critical section.  It is\r
+               possible for this to be in a critical section as calls to wait for\r
+               mutexes are accumulative. */\r
                if( ulCriticalNesting == 0 )\r
                {\r
                        SetEvent( pvInterruptEvent );\r