]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/Common/Minimal/GenQTest.c
Update version number to 8.1.1 for patch release that re-enables mutexes to be given...
[freertos] / FreeRTOS / Demo / Common / Minimal / GenQTest.c
index b306984d6dbca0f83583dce37cdb8a4a49d6dc0a..84ec6f8042ee237ea93479a65c3a58e71e0cc8ef 100644 (file)
@@ -1,48 +1,38 @@
 /*\r
-    FreeRTOS V7.4.0 - Copyright (C) 2013 Real Time Engineers Ltd.\r
+    FreeRTOS V8.1.1 - Copyright (C) 2014 Real Time Engineers Ltd.\r
+    All rights reserved\r
 \r
-    FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME.  PLEASE VISIT\r
-    http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
+    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
 \r
     ***************************************************************************\r
      *                                                                       *\r
-     *    FreeRTOS tutorial books are available in pdf and paperback.        *\r
-     *    Complete, revised, and edited pdf reference manuals are also       *\r
-     *    available.                                                         *\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
-     *    Purchasing FreeRTOS documentation will not only help you, by       *\r
-     *    ensuring you get running as quickly as possible and with an        *\r
-     *    in-depth knowledge of how to use FreeRTOS, it will also help       *\r
-     *    the FreeRTOS project to continue with its mission of providing     *\r
-     *    professional grade, cross platform, de facto standard solutions    *\r
-     *    for microcontrollers - completely free of charge!                  *\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
-     *    >>> See http://www.FreeRTOS.org/Documentation for details. <<<     *\r
-     *                                                                       *\r
-     *    Thank you for using FreeRTOS, and thank you for your support!      *\r
+     *    Thank you!                                                         *\r
      *                                                                       *\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
-    >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to\r
-    distribute a combined work that includes FreeRTOS without being obliged to\r
-    provide the source code for proprietary components outside of the FreeRTOS\r
-    kernel.\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
     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.  See the GNU General Public License for more\r
-    details. You should have received a copy of the GNU General Public License\r
-    and the FreeRTOS license exception along with FreeRTOS; if not itcan be\r
-    viewed here: http://www.freertos.org/a00114.html and also obtained by\r
-    writing to Real Time Engineers Ltd., contact details for whom are available\r
-    on the FreeRTOS WEB site.\r
+    FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
+    link: http://www.freertos.org/a00114.html\r
 \r
     1 tab == 4 spaces!\r
 \r
      *                                                                       *\r
     ***************************************************************************\r
 \r
-\r
-    http://www.FreeRTOS.org - Documentation, books, training, latest versions, \r
+    http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
     license and Real Time Engineers Ltd. contact details.\r
 \r
     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
-    including FreeRTOS+Trace - an indispensable productivity tool, and our new\r
-    fully thread aware and reentrant UDP/IP stack.\r
-\r
-    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High \r
-    Integrity Systems, who sell the code with commercial support, \r
-    indemnification and middleware, under the OpenRTOS brand.\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
+    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
+\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
     mission critical applications that require provable dependability.\r
+\r
+    1 tab == 4 spaces!\r
 */\r
 \r
 \r
-/* \r
- * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 - \r
- * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and \r
- * mutex behaviour. \r
+/*\r
+ * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -\r
+ * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and\r
+ * mutex behaviour.\r
  *\r
- * See the comments above the prvSendFrontAndBackTest() and \r
+ * See the comments above the prvSendFrontAndBackTest() and\r
  * prvLowPriorityMutexTask() prototypes below for more information.\r
  */\r
 \r
 #define genqMUTEX_MEDIUM_PRIORITY      ( tskIDLE_PRIORITY + 2 )\r
 #define genqMUTEX_HIGH_PRIORITY                ( tskIDLE_PRIORITY + 3 )\r
 \r
+#define genqINTERRUPT_MUTEX_GIVE_PERIOD_MS ( 100 )\r
 /*-----------------------------------------------------------*/\r
 \r
 /*\r
@@ -130,83 +122,121 @@ static void prvLowPriorityMutexTask( void *pvParameters );
 static void prvMediumPriorityMutexTask( void *pvParameters );\r
 static void prvHighPriorityMutexTask( void *pvParameters );\r
 \r
+/*\r
+ * Exercises the priority inheritance when a task takes two mutexes, returning\r
+ * them in a different order to which they were taken.\r
+ */\r
+static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );\r
+\r
+/*\r
+ * Exercises the priority inheritance when a task takes two mutexes, returning\r
+ * them in the same order in which they were taken.\r
+ */\r
+static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );\r
+\r
+/*\r
+ * Task that receives an a mutex that is given from an interrupt - although\r
+ * generally mutexes should not be used given in interrupts (and definitely\r
+ * never taken in an interrupt) there are some circumstances when it may be\r
+ * desirable.  NOTE:  This function is not declared static to prevent compiler\r
+ * warnings being generated in demos where the function is declared but not\r
+ * used.\r
+ */\r
+void vInterruptMutexTask( void *pvParameters );\r
+\r
 /*-----------------------------------------------------------*/\r
 \r
 /* Flag that will be latched to pdTRUE should any unexpected behaviour be\r
 detected in any of the tasks. */\r
-static portBASE_TYPE xErrorDetected = pdFALSE;\r
+static volatile BaseType_t xErrorDetected = pdFALSE;\r
 \r
 /* Counters that are incremented on each cycle of a test.  This is used to\r
 detect a stalled task - a test that is no longer running. */\r
-static volatile unsigned portLONG ulLoopCounter = 0;\r
-static volatile unsigned portLONG ulLoopCounter2 = 0;\r
+static volatile uint32_t ulLoopCounter = 0;\r
+static volatile uint32_t ulLoopCounter2 = 0;\r
 \r
 /* The variable that is guarded by the mutex in the mutex demo tasks. */\r
-static volatile unsigned portLONG ulGuardedVariable = 0;\r
+static volatile uint32_t ulGuardedVariable = 0;\r
 \r
 /* Handles used in the mutext test to suspend and resume the high and medium\r
 priority mutex test tasks. */\r
-static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;\r
+static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;\r
+\r
+/* A mutex which is given from an interrupt - although generally mutexes should\r
+not be used given in interrupts (and definitely never taken in an interrupt)\r
+there are some circumstances when it may be desirable. */\r
+static SemaphoreHandle_t xISRMutex = NULL;\r
 \r
 /*-----------------------------------------------------------*/\r
 \r
-void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )\r
+void vStartGenericQueueTasks( UBaseType_t uxPriority )\r
 {\r
-xQueueHandle xQueue;\r
-xSemaphoreHandle xMutex;\r
+QueueHandle_t xQueue;\r
+SemaphoreHandle_t xMutex;\r
+\r
+       xISRMutex = xSemaphoreCreateMutex();\r
+       configASSERT( xISRMutex );\r
 \r
        /* Create the queue that we are going to use for the\r
        prvSendFrontAndBackTest demo. */\r
-       xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );\r
+       xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );\r
 \r
        /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
-       in use.  The queue registry is provided as a means for kernel aware \r
+       in use.  The queue registry is provided as a means for kernel aware\r
        debuggers to locate queues and has no purpose if a kernel aware debugger\r
        is not being used.  The call to vQueueAddToRegistry() will be removed\r
-       by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
+       by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
        defined to be less than 1. */\r
-       vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );\r
+       vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );\r
 \r
        /* Create the demo task and pass it the queue just created.  We are\r
        passing the queue handle by value so it does not matter that it is\r
        declared on the stack here. */\r
-       xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );\r
+       xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );\r
 \r
        /* Create the mutex used by the prvMutexTest task. */\r
        xMutex = xSemaphoreCreateMutex();\r
 \r
        /* vQueueAddToRegistry() adds the mutex to the registry, if one is\r
-       in use.  The registry is provided as a means for kernel aware \r
+       in use.  The registry is provided as a means for kernel aware\r
        debuggers to locate mutexes and has no purpose if a kernel aware debugger\r
        is not being used.  The call to vQueueAddToRegistry() will be removed\r
-       by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is \r
+       by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
        defined to be less than 1. */\r
-       vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );\r
+       vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );\r
 \r
        /* Create the mutex demo tasks and pass it the mutex just created.  We are\r
        passing the mutex handle by value so it does not matter that it is declared\r
        on the stack here. */\r
-       xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );\r
-       xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );\r
-       xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );\r
+       xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );\r
+       xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );\r
+       xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );\r
+\r
+       /* Only when the windows simulator is being used - create the task that\r
+       receives a mutex from an interrupt. */\r
+       #ifdef _WINDOWS_\r
+       {\r
+               xTaskCreate( vInterruptMutexTask, "IntMu", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, NULL );\r
+       }\r
+       #endif /* __WINDOWS__ */\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
 static void prvSendFrontAndBackTest( void *pvParameters )\r
 {\r
-unsigned portLONG ulData, ulData2;\r
-xQueueHandle xQueue;\r
+uint32_t ulData, ulData2;\r
+QueueHandle_t xQueue;\r
 \r
        #ifdef USE_STDIO\r
-       void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
-       \r
-               const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";\r
+       void vPrintDisplayMessage( const char * const * ppcMessageToSend );\r
+\r
+               const char * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";\r
 \r
                /* Queue a message for printing to say the task has started. */\r
                vPrintDisplayMessage( &pcTaskStartMsg );\r
        #endif\r
 \r
-       xQueue = ( xQueueHandle ) pvParameters;\r
+       xQueue = ( QueueHandle_t ) pvParameters;\r
 \r
        for( ;; )\r
        {\r
@@ -321,7 +351,7 @@ xQueueHandle xQueue;
                        {\r
                                xErrorDetected = pdTRUE;\r
                        }\r
-                       \r
+\r
 \r
                        /* Now try receiving the data for real.  The value should be the\r
                        same.  Clobber the value first so we know we really received it. */\r
@@ -420,100 +450,293 @@ xQueueHandle xQueue;
 }\r
 /*-----------------------------------------------------------*/\r
 \r
-static void prvLowPriorityMutexTask( void *pvParameters )\r
+static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )\r
 {\r
-xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;\r
+       /* Take the mutex.  It should be available now. */\r
+       if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-       #ifdef USE_STDIO\r
-       void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
-       \r
-               const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";\r
+       /* Set the guarded variable to a known start value. */\r
+       ulGuardedVariable = 0;\r
 \r
-               /* Queue a message for printing to say the task has started. */\r
-               vPrintDisplayMessage( &pcTaskStartMsg );\r
+       /* This task's priority should be as per that assigned when the task was\r
+       created. */\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Now unsuspend the high priority task.  This will attempt to take the\r
+       mutex, and block when it finds it cannot obtain it. */\r
+       vTaskResume( xHighPriorityMutexTask );\r
+\r
+       #if configUSE_PREEMPTION == 0\r
+               taskYIELD();\r
        #endif\r
 \r
-       for( ;; )\r
+       /* Ensure the task is reporting its priority as blocked and not\r
+       suspended (as it would have done in versions up to V7.5.3). */\r
+       #if( INCLUDE_eTaskGetState == 1 )\r
        {\r
-               /* Take the mutex.  It should be available now. */\r
-               if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+               configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );\r
+       }\r
+       #endif /* INCLUDE_eTaskGetState */\r
 \r
-               /* Set our guarded variable to a known start value. */\r
-               ulGuardedVariable = 0;\r
+       /* The priority of the high priority task should now have been inherited\r
+       as by now it will have attempted to get the mutex. */\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* Our priority should be as per that assigned when the task was\r
-               created. */\r
-               if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       /* Attempt to set the priority of this task to the test priority -\r
+       between the     idle priority and the medium/high test priorities, but the\r
+       actual priority should remain at the high priority. */\r
+       vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* Now unsuspend the high priority task.  This will attempt to take the\r
-               mutex, and block when it finds it cannot obtain it. */\r
-               vTaskResume( xHighPriorityMutexTask );\r
+       /* Now unsuspend the medium priority task.  This should not run as the\r
+       inherited priority of this task is above that of the medium priority\r
+       task. */\r
+       vTaskResume( xMediumPriorityMutexTask );\r
 \r
-               /* We should now have inherited the prioritoy of the high priority task,\r
-               as by now it will have attempted to get the mutex. */\r
-               if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       /* If the medium priority task did run then it will have incremented the\r
+       guarded variable. */\r
+       if( ulGuardedVariable != 0 )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* We can attempt to set our priority to the test priority - between the\r
-               idle priority and the medium/high test priorities, but our actual\r
-               prioroity should remain at the high priority. */\r
-               vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );\r
-               if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       /* Take the local mutex too, so two mutexes are now held. */\r
+       if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* Now unsuspend the medium priority task.  This should not run as our\r
-               inherited priority is above that of the medium priority task. */\r
-               vTaskResume( xMediumPriorityMutexTask );\r
+       /* When the semaphore is given back the priority of this task should not\r
+       yet be disinherited because the local mutex is still held.  This is a\r
+       simplification to allow FreeRTOS to be integrated with middleware that\r
+       attempts to hold multiple mutexes without bloating the code with complex\r
+       algorithms.  It is possible that the high priority mutex task will\r
+       execute as it shares a priority with this task. */\r
+       if( xSemaphoreGive( xMutex ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* If the did run then it will have incremented our guarded variable. */\r
-               if( ulGuardedVariable != 0 )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       #if configUSE_PREEMPTION == 0\r
+               taskYIELD();\r
+       #endif\r
 \r
-               /* When we give back the semaphore our priority should be disinherited\r
-               back to the priority to which we attempted to set ourselves.  This means\r
-               that when the high priority task next blocks, the medium priority task\r
-               should execute and increment the guarded variable.   When we next run\r
-               both the high and medium priority tasks will have been suspended again. */\r
-               if( xSemaphoreGive( xMutex ) != pdPASS )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       /* The guarded variable is only incremented by the medium priority task,\r
+       which still should not have executed as this task should remain at the\r
+       higher priority, ensure this is the case. */\r
+       if( ulGuardedVariable != 0 )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* Check that the guarded variable did indeed increment... */\r
-               if( ulGuardedVariable != 1 )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
 \r
-               /* ... and that our priority has been disinherited to\r
-               genqMUTEX_TEST_PRIORITY. */\r
-               if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )\r
-               {\r
-                       xErrorDetected = pdTRUE;\r
-               }\r
+       /* Now also give back the local mutex, taking the held count back to 0.\r
+       This time the priority of this task should be disinherited back to the\r
+       priority to which it was set while the mutex was held.  This means\r
+       the medium priority task should execute and increment the guarded\r
+       variable.   When this task next runs both the high and medium priority\r
+       tasks will have been suspended again. */\r
+       if( xSemaphoreGive( xLocalMutex ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       #if configUSE_PREEMPTION == 0\r
+               taskYIELD();\r
+       #endif\r
+\r
+       /* Check the guarded variable did indeed increment... */\r
+       if( ulGuardedVariable != 1 )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* ... and that the priority of this task has been disinherited to\r
+       genqMUTEX_TEST_PRIORITY. */\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Set the priority of this task back to its original value, ready for\r
+       the next loop around this test. */\r
+       vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )\r
+{\r
+       /* Take the mutex.  It should be available now. */\r
+       if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Set the guarded variable to a known start value. */\r
+       ulGuardedVariable = 0;\r
+\r
+       /* This task's priority should be as per that assigned when the task was\r
+       created. */\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Now unsuspend the high priority task.  This will attempt to take the\r
+       mutex, and block when it finds it cannot obtain it. */\r
+       vTaskResume( xHighPriorityMutexTask );\r
+\r
+       #if configUSE_PREEMPTION == 0\r
+               taskYIELD();\r
+       #endif\r
+\r
+       /* Ensure the task is reporting its priority as blocked and not\r
+       suspended (as it would have done in versions up to V7.5.3). */\r
+       #if( INCLUDE_eTaskGetState == 1 )\r
+       {\r
+               configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );\r
+       }\r
+       #endif /* INCLUDE_eTaskGetState */\r
+\r
+       /* The priority of the high priority task should now have been inherited\r
+       as by now it will have attempted to get the mutex. */\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Now unsuspend the medium priority task.  This should not run as the\r
+       inherited priority of this task is above that of the medium priority\r
+       task. */\r
+       vTaskResume( xMediumPriorityMutexTask );\r
+\r
+       /* If the medium priority task did run then it will have incremented the\r
+       guarded variable. */\r
+       if( ulGuardedVariable != 0 )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Take the local mutex too, so two mutexes are now held. */\r
+       if( xSemaphoreTake( xLocalMutex, genqNO_BLOCK ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* When the local semaphore is given back the priority of this task should\r
+       not     yet be disinherited because the shared mutex is still held.  This is a\r
+       simplification to allow FreeRTOS to be integrated with middleware that\r
+       attempts to hold multiple mutexes without bloating the code with complex\r
+       algorithms.  It is possible that the high priority mutex task will\r
+       execute as it shares a priority with this task. */\r
+       if( xSemaphoreGive( xLocalMutex ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       #if configUSE_PREEMPTION == 0\r
+               taskYIELD();\r
+       #endif\r
+\r
+       /* The guarded variable is only incremented by the medium priority task,\r
+       which still should not have executed as this task should remain at the\r
+       higher priority, ensure this is the case. */\r
+       if( ulGuardedVariable != 0 )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* Now also give back the shared mutex, taking the held count back to 0.\r
+       This time the priority of this task should be disinherited back to the\r
+       priority at which it was created.  This means the medium priority task\r
+       should execute and increment the guarded variable.  When this task next runs\r
+       both the high and medium priority tasks will have been suspended again. */\r
+       if( xSemaphoreGive( xMutex ) != pdPASS )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       #if configUSE_PREEMPTION == 0\r
+               taskYIELD();\r
+       #endif\r
+\r
+       /* Check the guarded variable did indeed increment... */\r
+       if( ulGuardedVariable != 1 )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+\r
+       /* ... and that the priority of this task has been disinherited to\r
+       genqMUTEX_LOW_PRIORITY. */\r
+       if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+       {\r
+               xErrorDetected = pdTRUE;\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvLowPriorityMutexTask( void *pvParameters )\r
+{\r
+SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;\r
+\r
+       #ifdef USE_STDIO\r
+       void vPrintDisplayMessage( const char * const * ppcMessageToSend );\r
+\r
+               const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";\r
 \r
-               /* Set our priority back to our original priority ready for the next\r
-               loop around this test. */\r
-               vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );\r
+               /* Queue a message for printing to say the task has started. */\r
+               vPrintDisplayMessage( &pcTaskStartMsg );\r
+       #endif\r
+\r
+       /* The local mutex is used to check the 'mutexs held' count. */\r
+       xLocalMutex = xSemaphoreCreateMutex();\r
+       configASSERT( xLocalMutex );\r
+\r
+       for( ;; )\r
+       {\r
+               /* The first tests exercise the priority inheritance when two mutexes\r
+               are taken then returned in a different order to which they were\r
+               taken. */\r
+               prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );\r
 \r
-               /* Just to show we are still running. */\r
+               /* Just to show this task is still running. */\r
                ulLoopCounter2++;\r
 \r
                #if configUSE_PREEMPTION == 0\r
                        taskYIELD();\r
-               #endif          \r
+               #endif\r
+\r
+               /* The second tests exercise the priority inheritance when two mutexes\r
+               are taken then returned in the same order in which they were taken. */\r
+               prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );\r
+\r
+               /* Just to show this task is still running. */\r
+               ulLoopCounter2++;\r
+\r
+               #if configUSE_PREEMPTION == 0\r
+                       taskYIELD();\r
+               #endif\r
        }\r
 }\r
 /*-----------------------------------------------------------*/\r
@@ -538,7 +761,7 @@ static void prvMediumPriorityMutexTask( void *pvParameters )
 \r
 static void prvHighPriorityMutexTask( void *pvParameters )\r
 {\r
-xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;\r
+SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;\r
 \r
        for( ;; )\r
        {\r
@@ -554,22 +777,63 @@ xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
                        xErrorDetected = pdTRUE;\r
                }\r
 \r
-               /* When we eventually obtain the mutex we just give it back then\r
-               return to suspend ready for the next test. */\r
+               /* When the mutex is eventually obtained it is just given back before\r
+               returning to suspend ready for the next cycle. */\r
                if( xSemaphoreGive( xMutex ) != pdPASS )\r
                {\r
                        xErrorDetected = pdTRUE;\r
-               }               \r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* NOTE: This function is not declared static to prevent compiler warnings in\r
+demos where the function is declared but not used. */\r
+void vInterruptMutexTask( void *pvParameters )\r
+{\r
+const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( genqINTERRUPT_MUTEX_GIVE_PERIOD_MS );\r
+volatile uint32_t ulLoops = 0;\r
+\r
+       /* Just to avoid compiler warnings. */\r
+       ( void ) pvParameters;\r
+\r
+       for( ;; )\r
+       {\r
+               /* Has to wait longer than the time between gives to make sure it\r
+               should definitely have received the mutex. */\r
+               if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )\r
+               {\r
+                       xErrorDetected = pdTRUE;\r
+               }\r
+               else\r
+               {\r
+                       ulLoops++;\r
+               }\r
+       }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vMutexISRInteractionTest( void )\r
+{\r
+static TickType_t xLastGiveTime = 0;\r
+TickType_t xTimeNow;\r
+\r
+       xTimeNow = xTaskGetTickCountFromISR();\r
+       if( ( xTimeNow - xLastGiveTime ) >= pdMS_TO_TICKS( genqINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )\r
+       {\r
+               configASSERT( xISRMutex );\r
+               xSemaphoreGiveFromISR( xISRMutex, NULL );\r
+               xLastGiveTime = xTimeNow;\r
        }\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
 /* This is called to check that all the created tasks are still running. */\r
-portBASE_TYPE xAreGenericQueueTasksStillRunning( void )\r
+BaseType_t xAreGenericQueueTasksStillRunning( void )\r
 {\r
-static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;\r
+static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;\r
 \r
-       /* If the demo task is still running then we expect the loopcounters to\r
+       /* If the demo task is still running then we expect the loop counters to\r
        have incremented since this function was last called. */\r
        if( ulLastLoopCounter == ulLoopCounter )\r
        {\r
@@ -582,12 +846,12 @@ static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
        }\r
 \r
        ulLastLoopCounter = ulLoopCounter;\r
-       ulLastLoopCounter2 = ulLoopCounter2;    \r
+       ulLastLoopCounter2 = ulLoopCounter2;\r
 \r
        /* Errors detected in the task itself will have latched xErrorDetected\r
        to true. */\r
 \r
-       return ( portBASE_TYPE ) !xErrorDetected;\r
+       return ( BaseType_t ) !xErrorDetected;\r
 }\r
 \r
 \r