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