--- /dev/null
+/*\r
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.\r
+\r
+ This file is part of the FreeRTOS.org distribution.\r
+\r
+ FreeRTOS.org is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ FreeRTOS.org is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with FreeRTOS.org; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+ A special exception to the GPL can be applied should you wish to distribute\r
+ a combined work that includes FreeRTOS.org, without being obliged to provide\r
+ the source code for any proprietary components. See the licensing section\r
+ of http://www.FreeRTOS.org for full details of how and when the exception\r
+ can be applied.\r
+\r
+ ***************************************************************************\r
+ See http://www.FreeRTOS.org for documentation, latest information, license\r
+ and contact details. Please ensure to read the configuration and relevant\r
+ port sections of the online documentation.\r
+\r
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along\r
+ with commercial development and support options.\r
+ ***************************************************************************\r
+*/\r
+\r
+\r
+/* \r
+ * Tests the behaviour when data is peeked from a queue when there are\r
+ * multiple tasks blocked on the queue.\r
+ */\r
+\r
+\r
+#include <stdlib.h>\r
+\r
+/* Scheduler include files. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "queue.h"\r
+#include "semphr.h"\r
+\r
+/* Demo program include files. */\r
+#include "QPeek.h"\r
+\r
+#define qpeekQUEUE_LENGTH ( 5 )\r
+#define qpeekNO_BLOCK ( 0 )\r
+#define qpeekSHORT_DELAY ( 10 )\r
+\r
+#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )\r
+#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
+#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
+#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/*\r
+ * The following three tasks are used to demonstrate the peeking behaviour.\r
+ * Each task is given a different priority to demonstrate the order in which\r
+ * tasks are woken as data is peeked from a queue.\r
+ */\r
+static void prvLowPriorityPeekTask( void *pvParameters );\r
+static void prvMediumPriorityPeekTask( void *pvParameters );\r
+static void prvHighPriorityPeekTask( void *pvParameters );\r
+static void prvHighestPriorityPeekTask( 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
+\r
+/* Counter that is 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
+\r
+/* Handles to the test tasks. */\r
+xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;\r
+/*-----------------------------------------------------------*/\r
+\r
+void vStartQueuePeekTasks( void )\r
+{\r
+xQueueHandle xQueue;\r
+\r
+ /* Create the queue that we are going to use for the test/demo. */\r
+ xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( unsigned portLONG ) );\r
+\r
+ /* Create the demo tasks and pass it the queue just created. We are\r
+ passing the queue handle by value so it does not matter that it is declared\r
+ on the stack here. */\r
+ xTaskCreate( prvLowPriorityPeekTask, "PeekLow", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );\r
+ xTaskCreate( prvMediumPriorityPeekTask, "PeekMed", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );\r
+ xTaskCreate( prvHighPriorityPeekTask, "PeekHigh", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );\r
+ xTaskCreate( prvHighestPriorityPeekTask, "PeekHighest", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvHighestPriorityPeekTask( void *pvParameters )\r
+{\r
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
+unsigned portLONG ulValue;\r
+\r
+ #ifdef USE_STDIO\r
+ {\r
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );\r
+ \r
+ const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n";\r
+\r
+ /* Queue a message for printing to say the task has started. */\r
+ vPrintDisplayMessage( &pcTaskStartMsg );\r
+ }\r
+ #endif\r
+\r
+ for( ;; )\r
+ {\r
+ /* Try peeking from the queue. The queue should be empty so we will\r
+ block, allowing the high priority task to execute. */\r
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ /* We expected to have received something by the time we unblock. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* When we reach here the high and medium priority tasks should still\r
+ be blocked on the queue. We unblocked because the low priority task\r
+ wrote a value to the queue, which we should have peeked. Peeking the\r
+ data (rather than receiving it) will leave the data on the queue, so\r
+ the high priority task should then have also been unblocked, but not\r
+ yet executed. */\r
+ if( ulValue != 0x11223344 )\r
+ {\r
+ /* We did not receive the expected value. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
+ {\r
+ /* The message should have been left on the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Now we are going to actually receive the data, so when the high\r
+ priority task runs it will find the queue empty and return to the\r
+ blocked state. */\r
+ ulValue = 0;\r
+ if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
+ {\r
+ /* We expected to receive the value. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( ulValue != 0x11223344 )\r
+ {\r
+ /* We did not receive the expected value - which should have been\r
+ the same value as was peeked. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Now we will block again as the queue is once more empty. The low \r
+ priority task can then execute again. */\r
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ /* We expected to have received something by the time we unblock. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* When we get here the low priority task should have again written to the\r
+ queue. */\r
+ if( ulValue != 0x01234567 )\r
+ {\r
+ /* We did not receive the expected value. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
+ {\r
+ /* The message should have been left on the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* We only peeked the data, so suspending ourselves now should enable\r
+ the high priority task to also peek the data. The high priority task\r
+ will have been unblocked when we peeked the data as we left the data\r
+ in the queue. */\r
+ vTaskSuspend( NULL );\r
+\r
+\r
+\r
+ /* This time we are going to do the same as the above test, but the\r
+ high priority task is going to receive the data, rather than peek it.\r
+ This means that the medium priority task should never peek the value. */\r
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( ulValue != 0xaabbaabb )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ vTaskSuspend( NULL ); \r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvHighPriorityPeekTask( void *pvParameters )\r
+{\r
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
+unsigned portLONG ulValue;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Try peeking from the queue. The queue should be empty so we will\r
+ block, allowing the medium priority task to execute. Both the high\r
+ and highest priority tasks will then be blocked on the queue. */\r
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ /* We expected to have received something by the time we unblock. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* When we get here the highest priority task should have peeked the data\r
+ (unblocking this task) then suspended (allowing this task to also peek\r
+ the data). */\r
+ if( ulValue != 0x01234567 )\r
+ {\r
+ /* We did not receive the expected value. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
+ {\r
+ /* The message should have been left on the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* We only peeked the data, so suspending ourselves now should enable\r
+ the medium priority task to also peek the data. The medium priority task\r
+ will have been unblocked when we peeked the data as we left the data\r
+ in the queue. */\r
+ vTaskSuspend( NULL );\r
+\r
+\r
+ /* This time we are going actually receive the value, so the medium\r
+ priority task will never peek the data - we removed it from the queue. */\r
+ if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( ulValue != 0xaabbaabb )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ vTaskSuspend( NULL ); \r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvMediumPriorityPeekTask( void *pvParameters )\r
+{\r
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
+unsigned portLONG ulValue;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Try peeking from the queue. The queue should be empty so we will\r
+ block, allowing the low priority task to execute. The highest, high\r
+ and medium priority tasks will then all be blocked on the queue. */\r
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )\r
+ {\r
+ /* We expected to have received something by the time we unblock. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* When we get here the high priority task should have peeked the data\r
+ (unblocking this task) then suspended (allowing this task to also peek\r
+ the data). */\r
+ if( ulValue != 0x01234567 )\r
+ {\r
+ /* We did not receive the expected value. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
+ {\r
+ /* The message should have been left on the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Just so we know the test is still running. */\r
+ ulLoopCounter++;\r
+\r
+ /* Now we can suspend ourselves so the low priority task can execute\r
+ again. */\r
+ vTaskSuspend( NULL );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvLowPriorityPeekTask( void *pvParameters )\r
+{\r
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;\r
+unsigned portLONG ulValue;\r
+\r
+ for( ;; )\r
+ {\r
+ /* Write some data to the queue. This should unblock the highest \r
+ priority task that is waiting to peek data from the queue. */\r
+ ulValue = 0x11223344;\r
+ if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
+ {\r
+ /* We were expecting the queue to be empty so we should not of\r
+ had a problem writing to the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* By the time we get here the data should have been removed from\r
+ the queue. */\r
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Write another value to the queue, again waking the highest priority\r
+ task that is blocked on the queue. */\r
+ ulValue = 0x01234567;\r
+ if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
+ {\r
+ /* We were expecting the queue to be empty so we should not of\r
+ had a problem writing to the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* All the other tasks should now have successfully peeked the data.\r
+ The data is still in the queue so we should be able to receive it. */\r
+ ulValue = 0;\r
+ if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
+ {\r
+ /* We expected to receive the data. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ if( ulValue != 0x01234567 )\r
+ {\r
+ /* We did not receive the expected value. */\r
+ }\r
+ \r
+ /* Lets just delay a while as this is an intensive test as we don't\r
+ want to starve other tests of processing time. */\r
+ vTaskDelay( qpeekSHORT_DELAY );\r
+\r
+ /* Unsuspend the other tasks so we can repeat the test - this time\r
+ however not all the other tasks will peek the data as the high\r
+ priority task is actually going to remove it from the queue. Send\r
+ to front is used just to be different. As the queue is empty it\r
+ makes no difference to the result. */\r
+ vTaskResume( xMediumPriorityTask );\r
+ vTaskResume( xHighPriorityTask );\r
+ vTaskResume( xHighestPriorityTask );\r
+\r
+ ulValue = 0xaabbaabb;\r
+ if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )\r
+ {\r
+ /* We were expecting the queue to be empty so we should not of\r
+ had a problem writing to the queue. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* This time we should find that the queue is empty. The high priority\r
+ task actually removed the data rather than just peeking it. */\r
+ if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )\r
+ {\r
+ /* We expected to receive the data. */\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Unsuspend the highest and high priority tasks so we can go back\r
+ and repeat the whole thing. The medium priority task should not be\r
+ suspended as it was not able to peek the data in this last case. */\r
+ vTaskResume( xHighPriorityTask );\r
+ vTaskResume( xHighestPriorityTask ); \r
+\r
+ /* Lets just delay a while as this is an intensive test as we don't\r
+ want to starve other tests of processing time. */\r
+ vTaskDelay( qpeekSHORT_DELAY );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+/* This is called to check that all the created tasks are still running. */\r
+portBASE_TYPE xAreQueuePeekTasksStillRunning( void )\r
+{\r
+static unsigned portLONG ulLastLoopCounter = 0;\r
+\r
+ /* If the demo task is still running then we expect the loopcounter to\r
+ have incremented since this function was last called. */\r
+ if( ulLastLoopCounter == ulLoopCounter )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ ulLastLoopCounter = ulLoopCounter;\r
+\r
+ /* Errors detected in the task itself will have latched xErrorDetected\r
+ to true. */\r
+\r
+ return !xErrorDetected;\r
+}\r
+\r