2 FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
31 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
\r
32 with commercial development and support options.
\r
33 ***************************************************************************
\r
38 * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
\r
39 * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
\r
42 * See the comments above the prvSendFrontAndBackTest() and
\r
43 * prvLowPriorityMutexTask() prototypes below for more information.
\r
49 /* Scheduler include files. */
\r
50 #include "FreeRTOS.h"
\r
55 /* Demo program include files. */
\r
56 #include "GenQTest.h"
\r
58 #define genqQUEUE_LENGTH ( 5 )
\r
59 #define genqNO_BLOCK ( 0 )
\r
61 #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
\r
62 #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
\r
63 #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
\r
64 #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
\r
66 /*-----------------------------------------------------------*/
\r
69 * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
\r
70 * macros by using both to fill a queue, then reading from the queue to
\r
71 * check the resultant queue order is as expected. Queue data is also
\r
74 static void prvSendFrontAndBackTest( void *pvParameters );
\r
77 * The following three tasks are used to demonstrate the mutex behaviour.
\r
78 * Each task is given a different priority to demonstrate the priority
\r
79 * inheritance mechanism.
\r
81 * The low priority task obtains a mutex. After this a high priority task
\r
82 * attempts to obtain the same mutex, causing its priority to be inherited
\r
83 * by the low priority task. The task with the inherited high priority then
\r
84 * resumes a medium priority task to ensure it is not blocked by the medium
\r
85 * priority task while it holds the inherited high priority. Once the mutex
\r
86 * is returned the task with the inherited priority returns to its original
\r
87 * low priority, and is therefore immediately preempted by first the high
\r
88 * priority task and then the medium prioroity task before it can continue.
\r
90 static void prvLowPriorityMutexTask( void *pvParameters );
\r
91 static void prvMediumPriorityMutexTask( void *pvParameters );
\r
92 static void prvHighPriorityMutexTask( void *pvParameters );
\r
94 /*-----------------------------------------------------------*/
\r
96 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
\r
97 detected in any of the tasks. */
\r
98 static portBASE_TYPE xErrorDetected = pdFALSE;
\r
100 /* Counters that are incremented on each cycle of a test. This is used to
\r
101 detect a stalled task - a test that is no longer running. */
\r
102 static volatile unsigned portLONG ulLoopCounter = 0;
\r
103 static volatile unsigned portLONG ulLoopCounter2 = 0;
\r
105 /* The variable that is guarded by the mutex in the mutex demo tasks. */
\r
106 static volatile unsigned portLONG ulGuardedVariable = 0;
\r
108 /* Handles used in the mutext test to suspend and resume the high and medium
\r
109 priority mutex test tasks. */
\r
110 static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
\r
112 /*-----------------------------------------------------------*/
\r
114 void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
\r
116 xQueueHandle xQueue;
\r
117 xSemaphoreHandle xMutex;
\r
119 /* Create the queue that we are going to use for the
\r
120 prvSendFrontAndBackTest demo. */
\r
121 xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
\r
123 /* Create the demo task and pass it the queue just created. We are
\r
124 passing the queue handle by value so it does not matter that it is
\r
125 declared on the stack here. */
\r
126 xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
\r
128 /* Create the mutex used by the prvMutexTest task. */
\r
129 xMutex = xSemaphoreCreateMutex();
\r
131 /* Create the mutex demo tasks and pass it the mutex just created. We are
\r
132 passing the mutex handle by value so it does not matter that it is declared
\r
133 on the stack here. */
\r
134 xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
\r
135 xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
\r
136 xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
\r
138 /*-----------------------------------------------------------*/
\r
140 static void prvSendFrontAndBackTest( void *pvParameters )
\r
142 unsigned portLONG ulData, ulData2;
\r
143 xQueueHandle xQueue;
\r
146 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
148 const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
\r
150 /* Queue a message for printing to say the task has started. */
\r
151 vPrintDisplayMessage( &pcTaskStartMsg );
\r
154 xQueue = ( xQueueHandle ) pvParameters;
\r
158 /* The queue is empty, so sending an item to the back of the queue
\r
159 should have the same efect as sending it to the front of the queue.
\r
161 First send to the front and check everything is as expected. */
\r
162 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
\r
164 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
166 xErrorDetected = pdTRUE;
\r
169 if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
\r
171 xErrorDetected = pdTRUE;
\r
174 /* The data we sent to the queue should equal the data we just received
\r
176 if( ulLoopCounter != ulData )
\r
178 xErrorDetected = pdTRUE;
\r
181 /* Then do the same, sending the data to the back, checking everything
\r
183 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
185 xErrorDetected = pdTRUE;
\r
188 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
\r
190 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
192 xErrorDetected = pdTRUE;
\r
195 if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
\r
197 xErrorDetected = pdTRUE;
\r
200 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
202 xErrorDetected = pdTRUE;
\r
205 /* The data we sent to the queue should equal the data we just received
\r
207 if( ulLoopCounter != ulData )
\r
209 xErrorDetected = pdTRUE;
\r
212 #if configUSE_PREEMPTION == 0
\r
218 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
\r
219 for( ulData = 2; ulData < 5; ulData++ )
\r
221 xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
\r
224 /* Now the order in the queue should be 2, 3, 4, with 2 being the first
\r
225 thing to be read out. Now add 1 then 0 to the front of the queue. */
\r
226 if( uxQueueMessagesWaiting( xQueue ) != 3 )
\r
228 xErrorDetected = pdTRUE;
\r
231 xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
\r
233 xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
\r
235 /* Now the queue should be full, and when we read the data out we
\r
236 should receive 0, 1, 2, 3, 4. */
\r
237 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
239 xErrorDetected = pdTRUE;
\r
242 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
\r
244 xErrorDetected = pdTRUE;
\r
247 if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
\r
249 xErrorDetected = pdTRUE;
\r
252 #if configUSE_PREEMPTION == 0
\r
256 /* Check the data we read out is in the expected order. */
\r
257 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
\r
259 /* Try peeking the data first. */
\r
260 if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
\r
262 xErrorDetected = pdTRUE;
\r
265 if( ulData != ulData2 )
\r
267 xErrorDetected = pdTRUE;
\r
271 /* Now try receiving the data for real. The value should be the
\r
272 same. Clobber the value first so we know we really received it. */
\r
273 ulData2 = ~ulData2;
\r
274 if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
\r
276 xErrorDetected = pdTRUE;
\r
279 if( ulData != ulData2 )
\r
281 xErrorDetected = pdTRUE;
\r
285 /* The queue should now be empty again. */
\r
286 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
288 xErrorDetected = pdTRUE;
\r
291 #if configUSE_PREEMPTION == 0
\r
296 /* Our queue is empty once more, add 10, 11 to the back. */
\r
298 if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
\r
300 xErrorDetected = pdTRUE;
\r
303 if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
\r
305 xErrorDetected = pdTRUE;
\r
308 if( uxQueueMessagesWaiting( xQueue ) != 2 )
\r
310 xErrorDetected = pdTRUE;
\r
313 /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
\r
315 for( ulData = 9; ulData >= 7; ulData-- )
\r
317 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
\r
319 xErrorDetected = pdTRUE;
\r
323 /* Now check that the queue is full, and that receiving data provides
\r
324 the expected sequence of 7, 8, 9, 10, 11. */
\r
325 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
327 xErrorDetected = pdTRUE;
\r
330 if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
\r
332 xErrorDetected = pdTRUE;
\r
335 if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
\r
337 xErrorDetected = pdTRUE;
\r
340 #if configUSE_PREEMPTION == 0
\r
344 /* Check the data we read out is in the expected order. */
\r
345 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
\r
347 if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
\r
349 xErrorDetected = pdTRUE;
\r
352 if( ulData != ulData2 )
\r
354 xErrorDetected = pdTRUE;
\r
358 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
360 xErrorDetected = pdTRUE;
\r
366 /*-----------------------------------------------------------*/
\r
368 static void prvLowPriorityMutexTask( void *pvParameters )
\r
370 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
\r
373 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
375 const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
\r
377 /* Queue a message for printing to say the task has started. */
\r
378 vPrintDisplayMessage( &pcTaskStartMsg );
\r
383 /* Take the mutex. It should be available now. */
\r
384 if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )
\r
386 xErrorDetected = pdTRUE;
\r
389 /* Set our guarded variable to a known start value. */
\r
390 ulGuardedVariable = 0;
\r
392 /* Our priority should be as per that assigned when the task was
\r
394 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
396 xErrorDetected = pdTRUE;
\r
399 /* Now unsuspend the high priority task. This will attempt to take the
\r
400 mutex, and block when it finds it cannot obtain it. */
\r
401 vTaskResume( xHighPriorityMutexTask );
\r
403 /* We should now have inherited the prioritoy of the high priority task,
\r
404 as by now it will have attempted to get the mutex. */
\r
405 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
407 xErrorDetected = pdTRUE;
\r
410 /* We can attempt to set our priority to the test priority - between the
\r
411 idle priority and the medium/high test priorities, but our actual
\r
412 prioroity should remain at the high priority. */
\r
413 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
\r
414 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
416 xErrorDetected = pdTRUE;
\r
419 /* Now unsuspend the medium priority task. This should not run as our
\r
420 inherited priority is above that of the medium priority task. */
\r
421 vTaskResume( xMediumPriorityMutexTask );
\r
423 /* If the did run then it will have incremented our guarded variable. */
\r
424 if( ulGuardedVariable != 0 )
\r
426 xErrorDetected = pdTRUE;
\r
429 /* When we give back the semaphore our priority should be disinherited
\r
430 back to the priority to which we attempted to set ourselves. This means
\r
431 that when the high priority task next blocks, the medium priority task
\r
432 should execute and increment the guarded variable. When we next run
\r
433 both the high and medium priority tasks will have been suspended again. */
\r
434 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
436 xErrorDetected = pdTRUE;
\r
439 /* Check that the guarded variable did indeed increment... */
\r
440 if( ulGuardedVariable != 1 )
\r
442 xErrorDetected = pdTRUE;
\r
445 /* ... and that our priority has been disinherited to
\r
446 genqMUTEX_TEST_PRIORITY. */
\r
447 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
\r
449 xErrorDetected = pdTRUE;
\r
452 /* Set our priority back to our original priority ready for the next
\r
453 loop around this test. */
\r
454 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
\r
456 /* Just to show we are still running. */
\r
459 #if configUSE_PREEMPTION == 0
\r
464 /*-----------------------------------------------------------*/
\r
466 static void prvMediumPriorityMutexTask( void *pvParameters )
\r
470 /* The medium priority task starts by suspending itself. The low
\r
471 priority task will unsuspend this task when required. */
\r
472 vTaskSuspend( NULL );
\r
474 /* When this task unsuspends all it does is increment the guarded
\r
475 variable, this is so the low priority task knows that it has
\r
477 ulGuardedVariable++;
\r
480 /*-----------------------------------------------------------*/
\r
482 static void prvHighPriorityMutexTask( void *pvParameters )
\r
484 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
\r
488 /* The high priority task starts by suspending itself. The low
\r
489 priority task will unsuspend this task when required. */
\r
490 vTaskSuspend( NULL );
\r
492 /* When this task unsuspends all it does is attempt to obtain
\r
493 the mutex. It should find the mutex is not available so a
\r
494 block time is specified. */
\r
495 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
\r
497 xErrorDetected = pdTRUE;
\r
500 /* When we eventually obtain the mutex we just give it back then
\r
501 return to suspend ready for the next test. */
\r
502 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
504 xErrorDetected = pdTRUE;
\r
508 /*-----------------------------------------------------------*/
\r
510 /* This is called to check that all the created tasks are still running. */
\r
511 portBASE_TYPE xAreGenericQueueTasksStillRunning( void )
\r
513 static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
\r
515 /* If the demo task is still running then we expect the loopcounters to
\r
516 have incremented since this function was last called. */
\r
517 if( ulLastLoopCounter == ulLoopCounter )
\r
519 xErrorDetected = pdTRUE;
\r
522 if( ulLastLoopCounter2 == ulLoopCounter2 )
\r
524 xErrorDetected = pdTRUE;
\r
527 ulLastLoopCounter = ulLoopCounter;
\r
528 ulLastLoopCounter2 = ulLoopCounter2;
\r
530 /* Errors detected in the task itself will have latched xErrorDetected
\r
533 return !xErrorDetected;
\r