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