]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/GenQTest.c
Update version numbers in preparation for new release.
[freertos] / FreeRTOS / Demo / Common / Minimal / GenQTest.c
1 /*\r
2     FreeRTOS V8.2.2 - Copyright (C) 2015 Real Time Engineers Ltd.\r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     This file is part of the FreeRTOS distribution.\r
8 \r
9     FreeRTOS is free software; you can redistribute it and/or modify it under\r
10     the terms of the GNU General Public License (version 2) as published by the\r
11     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
12 \r
13     ***************************************************************************\r
14     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
15     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
16     >>!   obliged to provide the source code for proprietary components     !<<\r
17     >>!   outside of the FreeRTOS kernel.                                   !<<\r
18     ***************************************************************************\r
19 \r
20     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
21     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
22     FOR A PARTICULAR PURPOSE.  Full license text is available on the following\r
23     link: http://www.freertos.org/a00114.html\r
24 \r
25     ***************************************************************************\r
26      *                                                                       *\r
27      *    FreeRTOS provides completely free yet professionally developed,    *\r
28      *    robust, strictly quality controlled, supported, and cross          *\r
29      *    platform software that is more than just the market leader, it     *\r
30      *    is the industry's de facto standard.                               *\r
31      *                                                                       *\r
32      *    Help yourself get started quickly while simultaneously helping     *\r
33      *    to support the FreeRTOS project by purchasing a FreeRTOS           *\r
34      *    tutorial book, reference manual, or both:                          *\r
35      *    http://www.FreeRTOS.org/Documentation                              *\r
36      *                                                                       *\r
37     ***************************************************************************\r
38 \r
39     http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading\r
40     the FAQ page "My application does not run, what could be wrong?".  Have you\r
41     defined configASSERT()?\r
42 \r
43     http://www.FreeRTOS.org/support - In return for receiving this top quality\r
44     embedded software for free we request you assist our global community by\r
45     participating in the support forum.\r
46 \r
47     http://www.FreeRTOS.org/training - Investing in training allows your team to\r
48     be as productive as possible as early as possible.  Now you can receive\r
49     FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers\r
50     Ltd, and the world's leading authority on the world's leading RTOS.\r
51 \r
52     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
53     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
54     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
55 \r
56     http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.\r
57     Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.\r
58 \r
59     http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High\r
60     Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
61     licenses offer ticketed support, indemnification and commercial middleware.\r
62 \r
63     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
64     engineered and independently SIL3 certified version for use in safety and\r
65     mission critical applications that require provable dependability.\r
66 \r
67     1 tab == 4 spaces!\r
68 */\r
69 \r
70 \r
71 /*\r
72  * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -\r
73  * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and\r
74  * mutex behaviour.\r
75  *\r
76  * See the comments above the prvSendFrontAndBackTest() and\r
77  * prvLowPriorityMutexTask() prototypes below for more information.\r
78  */\r
79 \r
80 \r
81 #include <stdlib.h>\r
82 \r
83 /* Scheduler include files. */\r
84 #include "FreeRTOS.h"\r
85 #include "task.h"\r
86 #include "queue.h"\r
87 #include "semphr.h"\r
88 \r
89 /* Demo program include files. */\r
90 #include "GenQTest.h"\r
91 \r
92 #define genqQUEUE_LENGTH                ( 5 )\r
93 #define intsemNO_BLOCK                  ( 0 )\r
94 \r
95 #define genqMUTEX_LOW_PRIORITY          ( tskIDLE_PRIORITY )\r
96 #define genqMUTEX_TEST_PRIORITY         ( tskIDLE_PRIORITY + 1 )\r
97 #define genqMUTEX_MEDIUM_PRIORITY       ( tskIDLE_PRIORITY + 2 )\r
98 #define genqMUTEX_HIGH_PRIORITY         ( tskIDLE_PRIORITY + 3 )\r
99 \r
100 /*-----------------------------------------------------------*/\r
101 \r
102 /*\r
103  * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()\r
104  * macros by using both to fill a queue, then reading from the queue to\r
105  * check the resultant queue order is as expected.  Queue data is also\r
106  * peeked.\r
107  */\r
108 static void prvSendFrontAndBackTest( void *pvParameters );\r
109 \r
110 /*\r
111  * The following three tasks are used to demonstrate the mutex behaviour.\r
112  * Each task is given a different priority to demonstrate the priority\r
113  * inheritance mechanism.\r
114  *\r
115  * The low priority task obtains a mutex.  After this a high priority task\r
116  * attempts to obtain the same mutex, causing its priority to be inherited\r
117  * by the low priority task.  The task with the inherited high priority then\r
118  * resumes a medium priority task to ensure it is not blocked by the medium\r
119  * priority task while it holds the inherited high priority.  Once the mutex\r
120  * is returned the task with the inherited priority returns to its original\r
121  * low priority, and is therefore immediately preempted by first the high\r
122  * priority task and then the medium prioroity task before it can continue.\r
123  */\r
124 static void prvLowPriorityMutexTask( void *pvParameters );\r
125 static void prvMediumPriorityMutexTask( void *pvParameters );\r
126 static void prvHighPriorityMutexTask( void *pvParameters );\r
127 \r
128 /*-----------------------------------------------------------*/\r
129 \r
130 /* Flag that will be latched to pdTRUE should any unexpected behaviour be\r
131 detected in any of the tasks. */\r
132 static volatile BaseType_t xErrorDetected = pdFALSE;\r
133 \r
134 /* Counters that are incremented on each cycle of a test.  This is used to\r
135 detect a stalled task - a test that is no longer running. */\r
136 static volatile uint32_t ulLoopCounter = 0;\r
137 static volatile uint32_t ulLoopCounter2 = 0;\r
138 \r
139 /* The variable that is guarded by the mutex in the mutex demo tasks. */\r
140 static volatile uint32_t ulGuardedVariable = 0;\r
141 \r
142 /* Handles used in the mutext test to suspend and resume the high and medium\r
143 priority mutex test tasks. */\r
144 static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;\r
145 \r
146 /*-----------------------------------------------------------*/\r
147 \r
148 void vStartGenericQueueTasks( UBaseType_t uxPriority )\r
149 {\r
150 QueueHandle_t xQueue;\r
151 SemaphoreHandle_t xMutex;\r
152 \r
153 \r
154         /* Create the queue that we are going to use for the\r
155         prvSendFrontAndBackTest demo. */\r
156         xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );\r
157 \r
158         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
159         in use.  The queue registry is provided as a means for kernel aware\r
160         debuggers to locate queues and has no purpose if a kernel aware debugger\r
161         is not being used.  The call to vQueueAddToRegistry() will be removed\r
162         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
163         defined to be less than 1. */\r
164         vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );\r
165 \r
166         /* Create the demo task and pass it the queue just created.  We are\r
167         passing the queue handle by value so it does not matter that it is\r
168         declared on the stack here. */\r
169         xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );\r
170 \r
171         /* Create the mutex used by the prvMutexTest task. */\r
172         xMutex = xSemaphoreCreateMutex();\r
173 \r
174         /* vQueueAddToRegistry() adds the mutex to the registry, if one is\r
175         in use.  The registry is provided as a means for kernel aware\r
176         debuggers to locate mutexes and has no purpose if a kernel aware debugger\r
177         is not being used.  The call to vQueueAddToRegistry() will be removed\r
178         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
179         defined to be less than 1. */\r
180         vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );\r
181 \r
182         /* Create the mutex demo tasks and pass it the mutex just created.  We are\r
183         passing the mutex handle by value so it does not matter that it is declared\r
184         on the stack here. */\r
185         xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );\r
186         xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );\r
187         xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );\r
188 }\r
189 /*-----------------------------------------------------------*/\r
190 \r
191 static void prvSendFrontAndBackTest( void *pvParameters )\r
192 {\r
193 uint32_t ulData, ulData2;\r
194 QueueHandle_t xQueue;\r
195 \r
196         #ifdef USE_STDIO\r
197         void vPrintDisplayMessage( const char * const * ppcMessageToSend );\r
198 \r
199                 const char * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";\r
200 \r
201                 /* Queue a message for printing to say the task has started. */\r
202                 vPrintDisplayMessage( &pcTaskStartMsg );\r
203         #endif\r
204 \r
205         xQueue = ( QueueHandle_t ) pvParameters;\r
206 \r
207         for( ;; )\r
208         {\r
209                 /* The queue is empty, so sending an item to the back of the queue\r
210                 should have the same efect as sending it to the front of the queue.\r
211 \r
212                 First send to the front and check everything is as expected. */\r
213                 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );\r
214 \r
215                 if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
216                 {\r
217                         xErrorDetected = pdTRUE;\r
218                 }\r
219 \r
220                 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )\r
221                 {\r
222                         xErrorDetected = pdTRUE;\r
223                 }\r
224 \r
225                 /* The data we sent to the queue should equal the data we just received\r
226                 from the queue. */\r
227                 if( ulLoopCounter != ulData )\r
228                 {\r
229                         xErrorDetected = pdTRUE;\r
230                 }\r
231 \r
232                 /* Then do the same, sending the data to the back, checking everything\r
233                 is as expected. */\r
234                 if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
235                 {\r
236                         xErrorDetected = pdTRUE;\r
237                 }\r
238 \r
239                 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );\r
240 \r
241                 if( uxQueueMessagesWaiting( xQueue ) != 1 )\r
242                 {\r
243                         xErrorDetected = pdTRUE;\r
244                 }\r
245 \r
246                 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )\r
247                 {\r
248                         xErrorDetected = pdTRUE;\r
249                 }\r
250 \r
251                 if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
252                 {\r
253                         xErrorDetected = pdTRUE;\r
254                 }\r
255 \r
256                 /* The data we sent to the queue should equal the data we just received\r
257                 from the queue. */\r
258                 if( ulLoopCounter != ulData )\r
259                 {\r
260                         xErrorDetected = pdTRUE;\r
261                 }\r
262 \r
263                 #if configUSE_PREEMPTION == 0\r
264                         taskYIELD();\r
265                 #endif\r
266 \r
267 \r
268 \r
269                 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */\r
270                 for( ulData = 2; ulData < 5; ulData++ )\r
271                 {\r
272                         xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK );\r
273                 }\r
274 \r
275                 /* Now the order in the queue should be 2, 3, 4, with 2 being the first\r
276                 thing to be read out.  Now add 1 then 0 to the front of the queue. */\r
277                 if( uxQueueMessagesWaiting( xQueue ) != 3 )\r
278                 {\r
279                         xErrorDetected = pdTRUE;\r
280                 }\r
281                 ulData = 1;\r
282                 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );\r
283                 ulData = 0;\r
284                 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );\r
285 \r
286                 /* Now the queue should be full, and when we read the data out we\r
287                 should receive 0, 1, 2, 3, 4. */\r
288                 if( uxQueueMessagesWaiting( xQueue ) != 5 )\r
289                 {\r
290                         xErrorDetected = pdTRUE;\r
291                 }\r
292 \r
293                 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
294                 {\r
295                         xErrorDetected = pdTRUE;\r
296                 }\r
297 \r
298                 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
299                 {\r
300                         xErrorDetected = pdTRUE;\r
301                 }\r
302 \r
303                 #if configUSE_PREEMPTION == 0\r
304                         taskYIELD();\r
305                 #endif\r
306 \r
307                 /* Check the data we read out is in the expected order. */\r
308                 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )\r
309                 {\r
310                         /* Try peeking the data first. */\r
311                         if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )\r
312                         {\r
313                                 xErrorDetected = pdTRUE;\r
314                         }\r
315 \r
316                         if( ulData != ulData2 )\r
317                         {\r
318                                 xErrorDetected = pdTRUE;\r
319                         }\r
320 \r
321 \r
322                         /* Now try receiving the data for real.  The value should be the\r
323                         same.  Clobber the value first so we know we really received it. */\r
324                         ulData2 = ~ulData2;\r
325                         if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )\r
326                         {\r
327                                 xErrorDetected = pdTRUE;\r
328                         }\r
329 \r
330                         if( ulData != ulData2 )\r
331                         {\r
332                                 xErrorDetected = pdTRUE;\r
333                         }\r
334                 }\r
335 \r
336                 /* The queue should now be empty again. */\r
337                 if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
338                 {\r
339                         xErrorDetected = pdTRUE;\r
340                 }\r
341 \r
342                 #if configUSE_PREEMPTION == 0\r
343                         taskYIELD();\r
344                 #endif\r
345 \r
346 \r
347                 /* Our queue is empty once more, add 10, 11 to the back. */\r
348                 ulData = 10;\r
349                 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )\r
350                 {\r
351                         xErrorDetected = pdTRUE;\r
352                 }\r
353                 ulData = 11;\r
354                 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )\r
355                 {\r
356                         xErrorDetected = pdTRUE;\r
357                 }\r
358 \r
359                 if( uxQueueMessagesWaiting( xQueue ) != 2 )\r
360                 {\r
361                         xErrorDetected = pdTRUE;\r
362                 }\r
363 \r
364                 /* Now we should have 10, 11 in the queue.  Add 7, 8, 9 to the\r
365                 front. */\r
366                 for( ulData = 9; ulData >= 7; ulData-- )\r
367                 {\r
368                         if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )\r
369                         {\r
370                                 xErrorDetected = pdTRUE;\r
371                         }\r
372                 }\r
373 \r
374                 /* Now check that the queue is full, and that receiving data provides\r
375                 the expected sequence of 7, 8, 9, 10, 11. */\r
376                 if( uxQueueMessagesWaiting( xQueue ) != 5 )\r
377                 {\r
378                         xErrorDetected = pdTRUE;\r
379                 }\r
380 \r
381                 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
382                 {\r
383                         xErrorDetected = pdTRUE;\r
384                 }\r
385 \r
386                 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )\r
387                 {\r
388                         xErrorDetected = pdTRUE;\r
389                 }\r
390 \r
391                 #if configUSE_PREEMPTION == 0\r
392                         taskYIELD();\r
393                 #endif\r
394 \r
395                 /* Check the data we read out is in the expected order. */\r
396                 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )\r
397                 {\r
398                         if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )\r
399                         {\r
400                                 xErrorDetected = pdTRUE;\r
401                         }\r
402 \r
403                         if( ulData != ulData2 )\r
404                         {\r
405                                 xErrorDetected = pdTRUE;\r
406                         }\r
407                 }\r
408 \r
409                 if( uxQueueMessagesWaiting( xQueue ) != 0 )\r
410                 {\r
411                         xErrorDetected = pdTRUE;\r
412                 }\r
413 \r
414                 ulLoopCounter++;\r
415         }\r
416 }\r
417 /*-----------------------------------------------------------*/\r
418 \r
419 static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )\r
420 {\r
421         /* Take the mutex.  It should be available now. */\r
422         if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )\r
423         {\r
424                 xErrorDetected = pdTRUE;\r
425         }\r
426 \r
427         /* Set the guarded variable to a known start value. */\r
428         ulGuardedVariable = 0;\r
429 \r
430         /* This task's priority should be as per that assigned when the task was\r
431         created. */\r
432         if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
433         {\r
434                 xErrorDetected = pdTRUE;\r
435         }\r
436 \r
437         /* Now unsuspend the high priority task.  This will attempt to take the\r
438         mutex, and block when it finds it cannot obtain it. */\r
439         vTaskResume( xHighPriorityMutexTask );\r
440 \r
441         #if configUSE_PREEMPTION == 0\r
442                 taskYIELD();\r
443         #endif\r
444 \r
445         /* Ensure the task is reporting its priority as blocked and not\r
446         suspended (as it would have done in versions up to V7.5.3). */\r
447         #if( INCLUDE_eTaskGetState == 1 )\r
448         {\r
449                 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );\r
450         }\r
451         #endif /* INCLUDE_eTaskGetState */\r
452 \r
453         /* The priority of the high priority task should now have been inherited\r
454         as by now it will have attempted to get the mutex. */\r
455         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
456         {\r
457                 xErrorDetected = pdTRUE;\r
458         }\r
459 \r
460         /* Attempt to set the priority of this task to the test priority -\r
461         between the     idle priority and the medium/high test priorities, but the\r
462         actual priority should remain at the high priority. */\r
463         vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );\r
464         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
465         {\r
466                 xErrorDetected = pdTRUE;\r
467         }\r
468 \r
469         /* Now unsuspend the medium priority task.  This should not run as the\r
470         inherited priority of this task is above that of the medium priority\r
471         task. */\r
472         vTaskResume( xMediumPriorityMutexTask );\r
473 \r
474         /* If the medium priority task did run then it will have incremented the\r
475         guarded variable. */\r
476         if( ulGuardedVariable != 0 )\r
477         {\r
478                 xErrorDetected = pdTRUE;\r
479         }\r
480 \r
481         /* Take the local mutex too, so two mutexes are now held. */\r
482         if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )\r
483         {\r
484                 xErrorDetected = pdTRUE;\r
485         }\r
486 \r
487         /* When the semaphore is given back the priority of this task should not\r
488         yet be disinherited because the local mutex is still held.  This is a\r
489         simplification to allow FreeRTOS to be integrated with middleware that\r
490         attempts to hold multiple mutexes without bloating the code with complex\r
491         algorithms.  It is possible that the high priority mutex task will\r
492         execute as it shares a priority with this task. */\r
493         if( xSemaphoreGive( xMutex ) != pdPASS )\r
494         {\r
495                 xErrorDetected = pdTRUE;\r
496         }\r
497 \r
498         #if configUSE_PREEMPTION == 0\r
499                 taskYIELD();\r
500         #endif\r
501 \r
502         /* The guarded variable is only incremented by the medium priority task,\r
503         which still should not have executed as this task should remain at the\r
504         higher priority, ensure this is the case. */\r
505         if( ulGuardedVariable != 0 )\r
506         {\r
507                 xErrorDetected = pdTRUE;\r
508         }\r
509 \r
510         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
511         {\r
512                 xErrorDetected = pdTRUE;\r
513         }\r
514 \r
515         /* Now also give back the local mutex, taking the held count back to 0.\r
516         This time the priority of this task should be disinherited back to the\r
517         priority to which it was set while the mutex was held.  This means\r
518         the medium priority task should execute and increment the guarded\r
519         variable.   When this task next runs both the high and medium priority\r
520         tasks will have been suspended again. */\r
521         if( xSemaphoreGive( xLocalMutex ) != pdPASS )\r
522         {\r
523                 xErrorDetected = pdTRUE;\r
524         }\r
525 \r
526         #if configUSE_PREEMPTION == 0\r
527                 taskYIELD();\r
528         #endif\r
529 \r
530         /* Check the guarded variable did indeed increment... */\r
531         if( ulGuardedVariable != 1 )\r
532         {\r
533                 xErrorDetected = pdTRUE;\r
534         }\r
535 \r
536         /* ... and that the priority of this task has been disinherited to\r
537         genqMUTEX_TEST_PRIORITY. */\r
538         if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )\r
539         {\r
540                 xErrorDetected = pdTRUE;\r
541         }\r
542 \r
543         /* Set the priority of this task back to its original value, ready for\r
544         the next loop around this test. */\r
545         vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );\r
546 }\r
547 /*-----------------------------------------------------------*/\r
548 \r
549 static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )\r
550 {\r
551         /* Take the mutex.  It should be available now. */\r
552         if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )\r
553         {\r
554                 xErrorDetected = pdTRUE;\r
555         }\r
556 \r
557         /* Set the guarded variable to a known start value. */\r
558         ulGuardedVariable = 0;\r
559 \r
560         /* This task's priority should be as per that assigned when the task was\r
561         created. */\r
562         if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
563         {\r
564                 xErrorDetected = pdTRUE;\r
565         }\r
566 \r
567         /* Now unsuspend the high priority task.  This will attempt to take the\r
568         mutex, and block when it finds it cannot obtain it. */\r
569         vTaskResume( xHighPriorityMutexTask );\r
570 \r
571         #if configUSE_PREEMPTION == 0\r
572                 taskYIELD();\r
573         #endif\r
574 \r
575         /* Ensure the task is reporting its priority as blocked and not\r
576         suspended (as it would have done in versions up to V7.5.3). */\r
577         #if( INCLUDE_eTaskGetState == 1 )\r
578         {\r
579                 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );\r
580         }\r
581         #endif /* INCLUDE_eTaskGetState */\r
582 \r
583         /* The priority of the high priority task should now have been inherited\r
584         as by now it will have attempted to get the mutex. */\r
585         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
586         {\r
587                 xErrorDetected = pdTRUE;\r
588         }\r
589 \r
590         /* Now unsuspend the medium priority task.  This should not run as the\r
591         inherited priority of this task is above that of the medium priority\r
592         task. */\r
593         vTaskResume( xMediumPriorityMutexTask );\r
594 \r
595         /* If the medium priority task did run then it will have incremented the\r
596         guarded variable. */\r
597         if( ulGuardedVariable != 0 )\r
598         {\r
599                 xErrorDetected = pdTRUE;\r
600         }\r
601 \r
602         /* Take the local mutex too, so two mutexes are now held. */\r
603         if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )\r
604         {\r
605                 xErrorDetected = pdTRUE;\r
606         }\r
607 \r
608         /* When the local semaphore is given back the priority of this task should\r
609         not     yet be disinherited because the shared mutex is still held.  This is a\r
610         simplification to allow FreeRTOS to be integrated with middleware that\r
611         attempts to hold multiple mutexes without bloating the code with complex\r
612         algorithms.  It is possible that the high priority mutex task will\r
613         execute as it shares a priority with this task. */\r
614         if( xSemaphoreGive( xLocalMutex ) != pdPASS )\r
615         {\r
616                 xErrorDetected = pdTRUE;\r
617         }\r
618 \r
619         #if configUSE_PREEMPTION == 0\r
620                 taskYIELD();\r
621         #endif\r
622 \r
623         /* The guarded variable is only incremented by the medium priority task,\r
624         which still should not have executed as this task should remain at the\r
625         higher priority, ensure this is the case. */\r
626         if( ulGuardedVariable != 0 )\r
627         {\r
628                 xErrorDetected = pdTRUE;\r
629         }\r
630 \r
631         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )\r
632         {\r
633                 xErrorDetected = pdTRUE;\r
634         }\r
635 \r
636         /* Now also give back the shared mutex, taking the held count back to 0.\r
637         This time the priority of this task should be disinherited back to the\r
638         priority at which it was created.  This means the medium priority task\r
639         should execute and increment the guarded variable.  When this task next runs\r
640         both the high and medium priority tasks will have been suspended again. */\r
641         if( xSemaphoreGive( xMutex ) != pdPASS )\r
642         {\r
643                 xErrorDetected = pdTRUE;\r
644         }\r
645 \r
646         #if configUSE_PREEMPTION == 0\r
647                 taskYIELD();\r
648         #endif\r
649 \r
650         /* Check the guarded variable did indeed increment... */\r
651         if( ulGuardedVariable != 1 )\r
652         {\r
653                 xErrorDetected = pdTRUE;\r
654         }\r
655 \r
656         /* ... and that the priority of this task has been disinherited to\r
657         genqMUTEX_LOW_PRIORITY. */\r
658         if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )\r
659         {\r
660                 xErrorDetected = pdTRUE;\r
661         }\r
662 }\r
663 /*-----------------------------------------------------------*/\r
664 \r
665 static void prvLowPriorityMutexTask( void *pvParameters )\r
666 {\r
667 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;\r
668 \r
669         #ifdef USE_STDIO\r
670         void vPrintDisplayMessage( const char * const * ppcMessageToSend );\r
671 \r
672                 const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";\r
673 \r
674                 /* Queue a message for printing to say the task has started. */\r
675                 vPrintDisplayMessage( &pcTaskStartMsg );\r
676         #endif\r
677 \r
678         /* The local mutex is used to check the 'mutexs held' count. */\r
679         xLocalMutex = xSemaphoreCreateMutex();\r
680         configASSERT( xLocalMutex );\r
681 \r
682         for( ;; )\r
683         {\r
684                 /* The first tests exercise the priority inheritance when two mutexes\r
685                 are taken then returned in a different order to which they were\r
686                 taken. */\r
687                 prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );\r
688 \r
689                 /* Just to show this task is still running. */\r
690                 ulLoopCounter2++;\r
691 \r
692                 #if configUSE_PREEMPTION == 0\r
693                         taskYIELD();\r
694                 #endif\r
695 \r
696                 /* The second tests exercise the priority inheritance when two mutexes\r
697                 are taken then returned in the same order in which they were taken. */\r
698                 prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );\r
699 \r
700                 /* Just to show this task is still running. */\r
701                 ulLoopCounter2++;\r
702 \r
703                 #if configUSE_PREEMPTION == 0\r
704                         taskYIELD();\r
705                 #endif\r
706         }\r
707 }\r
708 /*-----------------------------------------------------------*/\r
709 \r
710 static void prvMediumPriorityMutexTask( void *pvParameters )\r
711 {\r
712         ( void ) pvParameters;\r
713 \r
714         for( ;; )\r
715         {\r
716                 /* The medium priority task starts by suspending itself.  The low\r
717                 priority task will unsuspend this task when required. */\r
718                 vTaskSuspend( NULL );\r
719 \r
720                 /* When this task unsuspends all it does is increment the guarded\r
721                 variable, this is so the low priority task knows that it has\r
722                 executed. */\r
723                 ulGuardedVariable++;\r
724         }\r
725 }\r
726 /*-----------------------------------------------------------*/\r
727 \r
728 static void prvHighPriorityMutexTask( void *pvParameters )\r
729 {\r
730 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;\r
731 \r
732         for( ;; )\r
733         {\r
734                 /* The high priority task starts by suspending itself.  The low\r
735                 priority task will unsuspend this task when required. */\r
736                 vTaskSuspend( NULL );\r
737 \r
738                 /* When this task unsuspends all it does is attempt to obtain\r
739                 the mutex.  It should find the mutex is not available so a\r
740                 block time is specified. */\r
741                 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )\r
742                 {\r
743                         xErrorDetected = pdTRUE;\r
744                 }\r
745 \r
746                 /* When the mutex is eventually obtained it is just given back before\r
747                 returning to suspend ready for the next cycle. */\r
748                 if( xSemaphoreGive( xMutex ) != pdPASS )\r
749                 {\r
750                         xErrorDetected = pdTRUE;\r
751                 }\r
752         }\r
753 }\r
754 /*-----------------------------------------------------------*/\r
755 \r
756 \r
757 /* This is called to check that all the created tasks are still running. */\r
758 BaseType_t xAreGenericQueueTasksStillRunning( void )\r
759 {\r
760 static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;\r
761 \r
762         /* If the demo task is still running then we expect the loop counters to\r
763         have incremented since this function was last called. */\r
764         if( ulLastLoopCounter == ulLoopCounter )\r
765         {\r
766                 xErrorDetected = pdTRUE;\r
767         }\r
768 \r
769         if( ulLastLoopCounter2 == ulLoopCounter2 )\r
770         {\r
771                 xErrorDetected = pdTRUE;\r
772         }\r
773 \r
774         ulLastLoopCounter = ulLoopCounter;\r
775         ulLastLoopCounter2 = ulLoopCounter2;\r
776 \r
777         /* Errors detected in the task itself will have latched xErrorDetected\r
778         to true. */\r
779 \r
780         return ( BaseType_t ) !xErrorDetected;\r
781 }\r
782 \r
783 \r