/*\r
- FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd.\r
+ FreeRTOS V9.0.0 - Copyright (C) 2016 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
- >>! NOTE: The modification to the GPL is included to allow you to distribute\r
- >>! a combined work that includes FreeRTOS without being obliged to provide\r
- >>! the source code for proprietary components outside of the FreeRTOS\r
- >>! kernel.\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
* prvLowPriorityMutexTask() prototypes below for more information.\r
*/\r
\r
-\r
+/* Standard includes. */\r
#include <stdlib.h>\r
\r
/* Scheduler include files. */\r
#include "GenQTest.h"\r
\r
#define genqQUEUE_LENGTH ( 5 )\r
-#define genqNO_BLOCK ( 0 )\r
+#define intsemNO_BLOCK ( 0 )\r
+#define genqSHORT_BLOCK ( pdMS_TO_TICKS( 2 ) )\r
\r
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )\r
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
* priority task while it holds the inherited high priority. Once the mutex\r
* is returned the task with the inherited priority returns to its original\r
* low priority, and is therefore immediately preempted by first the high\r
- * priority task and then the medium prioroity task before it can continue.\r
+ * priority task and then the medium priority task before it can continue.\r
*/\r
static void prvLowPriorityMutexTask( void *pvParameters );\r
static void prvMediumPriorityMutexTask( void *pvParameters );\r
static void prvHighPriorityMutexTask( void *pvParameters );\r
\r
+/*\r
+ * Tests the behaviour when a low priority task inherits the priority of a\r
+ * higher priority task when taking two mutexes, and returns the mutexes in\r
+ * first the same order as the two mutexes were obtained, and second the\r
+ * opposite order as the two mutexes were obtained.\r
+ */\r
+static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );\r
+static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );\r
+\r
+#if( INCLUDE_xTaskAbortDelay == 1 )\r
+\r
+ #if( configUSE_PREEMPTION == 0 )\r
+ #error The additional tests included when INCLUDE_xTaskAbortDelay is 1 expect preemption to be used.\r
+ #endif\r
+\r
+ /* Tests the behaviour when a low priority task inherits the priority of a\r
+ high priority task only for the high priority task to timeout before\r
+ obtaining the mutex. */\r
+ static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex );\r
+#endif\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 volatile 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 long ulLoopCounter = 0;\r
-static volatile unsigned long 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 long 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
+/* Handles used in the mutex 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
+/* If INCLUDE_xTaskAbortDelay is 1 additional tests are performed, requiring an\r
+additional task. */\r
+#if( INCLUDE_xTaskAbortDelay == 1 )\r
+ static TaskHandle_t xSecondMediumPriorityMutexTask;\r
+#endif\r
+\r
+/* Lets the high priority semaphore task know that its wait for the semaphore\r
+was aborted, in which case not being able to obtain the semaphore is not to be\r
+considered an error. */\r
+static volatile BaseType_t xBlockWasAborted = pdFALSE;\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
/* Create the queue that we are going to use for the\r
prvSendFrontAndBackTest demo. */\r
- xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned long ) );\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
- 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
- defined to be less than 1. */\r
- vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );\r
+ xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );\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, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );\r
+ if( xQueue != NULL )\r
+ {\r
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one\r
+ is 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
+ defined to be less than 1. */\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, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );\r
+ }\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
- 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
- defined to be less than 1. */\r
- vQueueAddToRegistry( ( xQueueHandle ) 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, "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
+ if( xMutex != NULL )\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
+ debuggers to locate mutexes and has no purpose if a kernel aware\r
+ debugger is not being used. The call to vQueueAddToRegistry() will be\r
+ removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not\r
+ defined or is defined to be less than 1. */\r
+ vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );\r
+\r
+ /* Create the mutex demo tasks and pass it the mutex just created. We\r
+ are passing the mutex handle by value so it does not matter that it is\r
+ declared on the stack here. */\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
+ /* If INCLUDE_xTaskAbortDelay is set then additional tests are performed,\r
+ requiring two instances of prvHighPriorityMutexTask(). */\r
+ #if( INCLUDE_xTaskAbortDelay == 1 )\r
+ {\r
+ xTaskCreate( prvHighPriorityMutexTask, "MuHigh2", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_MEDIUM_PRIORITY, &xSecondMediumPriorityMutexTask );\r
+ }\r
+ #endif /* INCLUDE_xTaskAbortDelay */\r
+ }\r
}\r
/*-----------------------------------------------------------*/\r
\r
static void prvSendFrontAndBackTest( void *pvParameters )\r
{\r
-unsigned long ulData, ulData2;\r
-xQueueHandle xQueue;\r
+uint32_t ulData, ulData2, ulLoopCounterSnapshot;\r
+QueueHandle_t xQueue;\r
\r
#ifdef USE_STDIO\r
void vPrintDisplayMessage( const char * const * ppcMessageToSend );\r
vPrintDisplayMessage( &pcTaskStartMsg );\r
#endif\r
\r
- xQueue = ( xQueueHandle ) pvParameters;\r
+ xQueue = ( QueueHandle_t ) pvParameters;\r
\r
for( ;; )\r
{\r
should have the same efect as sending it to the front of the queue.\r
\r
First send to the front and check everything is as expected. */\r
- xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );\r
+ ulLoopCounterSnapshot = ulLoopCounter;\r
+ xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );\r
\r
if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
xErrorDetected = pdTRUE;\r
}\r
\r
- xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );\r
+ ulLoopCounterSnapshot = ulLoopCounter;\r
+ xQueueSendToBack( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );\r
\r
if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
xErrorDetected = pdTRUE;\r
}\r
\r
- /* The data we sent to the queue should equal the data we just received\r
- from the queue. */\r
+ /* The data sent to the queue should equal the data just received from\r
+ the queue. */\r
if( ulLoopCounter != ulData )\r
{\r
xErrorDetected = pdTRUE;\r
/* Place 2, 3, 4 into the queue, adding items to the back of the queue. */\r
for( ulData = 2; ulData < 5; ulData++ )\r
{\r
- xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );\r
+ xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK );\r
}\r
\r
/* Now the order in the queue should be 2, 3, 4, with 2 being the first\r
xErrorDetected = pdTRUE;\r
}\r
ulData = 1;\r
- xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );\r
+ xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );\r
ulData = 0;\r
- xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );\r
+ xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );\r
\r
/* Now the queue should be full, and when we read the data out we\r
should receive 0, 1, 2, 3, 4. */\r
xErrorDetected = pdTRUE;\r
}\r
\r
- if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
+ if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
+ if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )\r
{\r
/* Try peeking the data first. */\r
- if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\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
ulData2 = ~ulData2;\r
- if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
/* Our queue is empty once more, add 10, 11 to the back. */\r
ulData = 10;\r
- if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
ulData = 11;\r
- if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
front. */\r
for( ulData = 9; ulData >= 7; ulData-- )\r
{\r
- if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
xErrorDetected = pdTRUE;\r
}\r
\r
- if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
+ if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )\r
+ if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
/* Check the data we read out is in the expected order. */\r
for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )\r
{\r
- if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )\r
+ if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
xErrorDetected = pdTRUE;\r
}\r
\r
+ /* Increment the loop counter to indicate these tasks are still\r
+ executing. */\r
ulLoopCounter++;\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
-static void prvLowPriorityMutexTask( void *pvParameters )\r
-{\r
-xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;\r
-\r
- #ifdef USE_STDIO\r
- void vPrintDisplayMessage( const char * const * ppcMessageToSend );\r
+#if( INCLUDE_xTaskAbortDelay == 1 )\r
\r
- const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";\r
+ static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex )\r
+ {\r
+ static UBaseType_t uxLoopCount = 0;\r
\r
- /* Queue a message for printing to say the task has started. */\r
- vPrintDisplayMessage( &pcTaskStartMsg );\r
- #endif\r
+ /* The tests in this function are very similar, the slight variations\r
+ are for code coverage purposes. */\r
\r
- for( ;; )\r
- {\r
/* Take the mutex. It should be available now. */\r
- if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )\r
+ if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- /* Set our guarded variable to a known start value. */\r
- ulGuardedVariable = 0;\r
-\r
- /* Our priority should be as per that assigned when the task was\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
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 it 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
+ /* This task should now have inherited the priority of the high priority\r
+ task as by now the high priority task will have attempted to obtain the\r
+ mutex. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
{\r
- configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );\r
+ xErrorDetected = pdTRUE;\r
}\r
- #endif /* INCLUDE_eTaskGetState */\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
+ /* Unblock a second medium priority task. It too will attempt to take\r
+ the mutex and enter the Blocked state - it won't run yet though as this\r
+ task has inherited a priority above it. */\r
+ vTaskResume( xSecondMediumPriorityMutexTask );\r
+\r
+ /* This task should still have the priority of the high priority task as\r
+ that had already been inherited as is the highest priority of the three\r
+ tasks using the mutex. */\r
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\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
+ /* On some loops, block for a short while to provide additional\r
+ code coverage. Blocking here will allow the medium priority task to\r
+ execute and so also block on the mutex so when the high priority task\r
+ causes this task to disinherit the high priority it is inherited down to\r
+ the priority of the medium priority task. When there is no delay the\r
+ medium priority task will not run until after the disinheritance, so\r
+ this task will disinherit back to its base priority, then only up to the\r
+ medium priority after the medium priority has executed. */\r
+ vTaskDelay( uxLoopCount & ( UBaseType_t ) 0x07 );\r
+\r
+ /* Now force the high priority task to unblock. It will fail to obtain\r
+ the mutex and go back to the suspended state - allowing this task to\r
+ execute again. xBlockWasAborted is set to pdTRUE so the higher priority\r
+ task knows that its failure to obtain the semaphore is not an error. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This task has inherited the priority of xHighPriorityMutexTask so\r
+ could still be running even though xHighPriorityMutexTask is no longer\r
+ blocked. Delay for a short while to ensure xHighPriorityMutexTask gets\r
+ a chance to run - indicated by this task changing priority. It should\r
+ disinherit the high priority task, but then inherit the priority of the\r
+ medium priority task that is waiting for the same mutex. */\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* Now force the medium priority task to unblock. xBlockWasAborted is\r
+ set to pdTRUE so the medium priority task knows that its failure to\r
+ obtain the semaphore is not an error. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != 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
+ /* This time no other tasks are waiting for the mutex, so this task\r
+ should return to its base priority. This might not happen straight\r
+ away as it is running at the same priority as the task it just\r
+ unblocked. */\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* Give the semaphore back ready for the next test. */\r
+ xSemaphoreGive( xMutex );\r
+\r
+ configASSERT( xErrorDetected == pdFALSE );\r
+\r
\r
- /* If the did run then it will have incremented our guarded variable. */\r
- if( ulGuardedVariable != 0 )\r
+\r
+ /* Now do the same again, but this time unsuspend the tasks in the\r
+ opposite order. This takes a different path though the code because\r
+ when the high priority task has its block aborted there is already\r
+ another task in the list of tasks waiting for the mutex, and the\r
+ low priority task drops down to that priority, rather than dropping\r
+ down to its base priority before inheriting the priority of the medium\r
+ priority task. */\r
+ if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\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
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
{\r
xErrorDetected = pdTRUE;\r
}\r
\r
- #if configUSE_PREEMPTION == 0\r
- taskYIELD();\r
- #endif\r
+ /* This time unsuspend the medium priority task first. This will\r
+ attempt to take the mutex, and block when it finds it cannot obtain it. */\r
+ vTaskResume( xSecondMediumPriorityMutexTask );\r
+\r
+ /* This time this task should now have inherited the priority of the\r
+ medium task. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This time the high priority task in unsuspended second. */\r
+ vTaskResume( xHighPriorityMutexTask );\r
\r
- /* Check that the guarded variable did indeed increment... */\r
- if( ulGuardedVariable != 1 )\r
+ /* The high priority task should already have run, causing this task to\r
+ inherit a priority for the second time. */\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
+ /* This time, when the high priority task has its delay aborted and it\r
+ fails to obtain the mutex this task will immediately have its priority\r
+ lowered down to that of the highest priority task waiting on the mutex,\r
+ which is the medium priority task. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )\r
{\r
xErrorDetected = pdTRUE;\r
}\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
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* And finally, when the medium priority task also have its delay\r
+ aborted there are no other tasks waiting for the mutex so this task\r
+ returns to its base priority. */\r
+ xBlockWasAborted = pdTRUE;\r
+ if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
+ {\r
+ /* If this task gets stuck here then the check variables will stop\r
+ incrementing and the check task will detect the error. */\r
+ vTaskDelay( genqSHORT_BLOCK );\r
+ }\r
+\r
+ /* Give the semaphore back ready for the next test. */\r
+ xSemaphoreGive( xMutex );\r
+\r
+ configASSERT( xErrorDetected == pdFALSE );\r
+\r
+ /* uxLoopCount is used to add a variable delay, and in-so-doing provide\r
+ additional code coverage. */\r
+ uxLoopCount++;\r
+ }\r
+\r
+#endif /* INCLUDE_xTaskAbortDelay == 1 */\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )\r
+{\r
+ /* Take the mutex. It should be available now. */\r
+ if( xSemaphoreTake( xMutex, intsemNO_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
+ /* This task should now have inherited the priority of the high priority\r
+ task as by now the high priority task will have attempted to obtain the\r
+ mutex. */\r
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\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 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, intsemNO_BLOCK ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
\r
- /* Just to show we are still running. */\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 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 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, intsemNO_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
+ /* This task should now have inherited the priority of the high priority\r
+ task as by now the high priority task will have attempted to obtain the\r
+ 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, intsemNO_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
+ /* 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 this task is still running. */\r
+ ulLoopCounter2++;\r
+\r
+ #if configUSE_PREEMPTION == 0\r
+ taskYIELD();\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
+ #if( INCLUDE_xTaskAbortDelay == 1 )\r
+ {\r
+ /* Tests the behaviour when a low priority task inherits the\r
+ priority of a high priority task only for the high priority task to\r
+ timeout before obtaining the mutex. */\r
+ prvHighPriorityTimeout( xMutex );\r
+ }\r
+ #endif\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
static void prvHighPriorityMutexTask( void *pvParameters )\r
{\r
-xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;\r
+SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;\r
\r
for( ;; )\r
{\r
priority task will unsuspend this task when required. */\r
vTaskSuspend( NULL );\r
\r
- /* When this task unsuspends all it does is attempt to obtain\r
- the mutex. It should find the mutex is not available so a\r
- block time is specified. */\r
+ /* When this task unsuspends all it does is attempt to obtain the\r
+ mutex. It should find the mutex is not available so a block time is\r
+ specified. */\r
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )\r
{\r
- xErrorDetected = pdTRUE;\r
+ /* This task would expect to obtain the mutex unless its wait for\r
+ the mutex was aborted. */\r
+ if( xBlockWasAborted == pdFALSE )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+ else\r
+ {\r
+ xBlockWasAborted = pdFALSE;\r
+ }\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
- if( xSemaphoreGive( xMutex ) != pdPASS )\r
+ else\r
{\r
- xErrorDetected = pdTRUE;\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
+\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 long 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
/* 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