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