2 FreeRTOS V9.0.0rc2 - Copyright (C) 2016 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\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
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
72 * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
\r
73 * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
\r
76 * See the comments above the prvSendFrontAndBackTest() and
\r
77 * prvLowPriorityMutexTask() prototypes below for more information.
\r
80 /* Standard includes. */
\r
83 /* Scheduler include files. */
\r
84 #include "FreeRTOS.h"
\r
89 /* Demo program include files. */
\r
90 #include "GenQTest.h"
\r
92 #define genqQUEUE_LENGTH ( 5 )
\r
93 #define intsemNO_BLOCK ( 0 )
\r
95 #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
\r
96 #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
\r
97 #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
\r
98 #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
\r
100 /*-----------------------------------------------------------*/
\r
103 * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
\r
104 * macros by using both to fill a queue, then reading from the queue to
\r
105 * check the resultant queue order is as expected. Queue data is also
\r
108 static void prvSendFrontAndBackTest( void *pvParameters );
\r
111 * The following three tasks are used to demonstrate the mutex behaviour.
\r
112 * Each task is given a different priority to demonstrate the priority
\r
113 * inheritance mechanism.
\r
115 * The low priority task obtains a mutex. After this a high priority task
\r
116 * attempts to obtain the same mutex, causing its priority to be inherited
\r
117 * by the low priority task. The task with the inherited high priority then
\r
118 * resumes a medium priority task to ensure it is not blocked by the medium
\r
119 * priority task while it holds the inherited high priority. Once the mutex
\r
120 * is returned the task with the inherited priority returns to its original
\r
121 * low priority, and is therefore immediately preempted by first the high
\r
122 * priority task and then the medium priority task before it can continue.
\r
124 static void prvLowPriorityMutexTask( void *pvParameters );
\r
125 static void prvMediumPriorityMutexTask( void *pvParameters );
\r
126 static void prvHighPriorityMutexTask( void *pvParameters );
\r
128 /*-----------------------------------------------------------*/
\r
130 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
\r
131 detected in any of the tasks. */
\r
132 static volatile BaseType_t xErrorDetected = pdFALSE;
\r
134 /* Counters that are incremented on each cycle of a test. This is used to
\r
135 detect a stalled task - a test that is no longer running. */
\r
136 static volatile uint32_t ulLoopCounter = 0;
\r
137 static volatile uint32_t ulLoopCounter2 = 0;
\r
139 /* The variable that is guarded by the mutex in the mutex demo tasks. */
\r
140 static volatile uint32_t ulGuardedVariable = 0;
\r
142 /* Handles used in the mutex test to suspend and resume the high and medium
\r
143 priority mutex test tasks. */
\r
144 static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
\r
146 /*-----------------------------------------------------------*/
\r
148 void vStartGenericQueueTasks( UBaseType_t uxPriority )
\r
150 QueueHandle_t xQueue;
\r
151 SemaphoreHandle_t xMutex;
\r
153 /* Create the queue that we are going to use for the
\r
154 prvSendFrontAndBackTest demo. */
\r
155 xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );
\r
157 if( xQueue != NULL )
\r
159 /* vQueueAddToRegistry() adds the queue to the queue registry, if one
\r
160 is in use. The queue registry is provided as a means for kernel aware
\r
161 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
162 is not being used. The call to vQueueAddToRegistry() will be removed
\r
163 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
164 defined to be less than 1. */
\r
165 vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );
\r
167 /* Create the demo task and pass it the queue just created. We are
\r
168 passing the queue handle by value so it does not matter that it is
\r
169 declared on the stack here. */
\r
170 xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
\r
173 /* Create the mutex used by the prvMutexTest task. */
\r
174 xMutex = xSemaphoreCreateMutex();
\r
176 if( xMutex != NULL )
\r
178 /* vQueueAddToRegistry() adds the mutex to the registry, if one is
\r
179 in use. The registry is provided as a means for kernel aware
\r
180 debuggers to locate mutexes and has no purpose if a kernel aware
\r
181 debugger is not being used. The call to vQueueAddToRegistry() will be
\r
182 removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
\r
183 defined or is defined to be less than 1. */
\r
184 vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );
\r
186 /* Create the mutex demo tasks and pass it the mutex just created. We
\r
187 are passing the mutex handle by value so it does not matter that it is
\r
188 declared on the stack here. */
\r
189 xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
\r
190 xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
\r
191 xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
\r
194 /*-----------------------------------------------------------*/
\r
196 static void prvSendFrontAndBackTest( void *pvParameters )
\r
198 uint32_t ulData, ulData2;
\r
199 QueueHandle_t xQueue;
\r
202 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
204 const char * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
\r
206 /* Queue a message for printing to say the task has started. */
\r
207 vPrintDisplayMessage( &pcTaskStartMsg );
\r
210 xQueue = ( QueueHandle_t ) pvParameters;
\r
214 /* The queue is empty, so sending an item to the back of the queue
\r
215 should have the same efect as sending it to the front of the queue.
\r
217 First send to the front and check everything is as expected. */
\r
218 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
\r
220 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
222 xErrorDetected = pdTRUE;
\r
225 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
227 xErrorDetected = pdTRUE;
\r
230 /* The data we sent to the queue should equal the data we just received
\r
232 if( ulLoopCounter != ulData )
\r
234 xErrorDetected = pdTRUE;
\r
237 /* Then do the same, sending the data to the back, checking everything
\r
239 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
241 xErrorDetected = pdTRUE;
\r
244 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
\r
246 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
248 xErrorDetected = pdTRUE;
\r
251 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
253 xErrorDetected = pdTRUE;
\r
256 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
258 xErrorDetected = pdTRUE;
\r
261 /* The data we sent to the queue should equal the data we just received
\r
263 if( ulLoopCounter != ulData )
\r
265 xErrorDetected = pdTRUE;
\r
268 #if configUSE_PREEMPTION == 0
\r
274 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
\r
275 for( ulData = 2; ulData < 5; ulData++ )
\r
277 xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
280 /* Now the order in the queue should be 2, 3, 4, with 2 being the first
\r
281 thing to be read out. Now add 1 then 0 to the front of the queue. */
\r
282 if( uxQueueMessagesWaiting( xQueue ) != 3 )
\r
284 xErrorDetected = pdTRUE;
\r
287 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
289 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
291 /* Now the queue should be full, and when we read the data out we
\r
292 should receive 0, 1, 2, 3, 4. */
\r
293 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
295 xErrorDetected = pdTRUE;
\r
298 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
300 xErrorDetected = pdTRUE;
\r
303 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
305 xErrorDetected = pdTRUE;
\r
308 #if configUSE_PREEMPTION == 0
\r
312 /* Check the data we read out is in the expected order. */
\r
313 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
\r
315 /* Try peeking the data first. */
\r
316 if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
318 xErrorDetected = pdTRUE;
\r
321 if( ulData != ulData2 )
\r
323 xErrorDetected = pdTRUE;
\r
327 /* Now try receiving the data for real. The value should be the
\r
328 same. Clobber the value first so we know we really received it. */
\r
329 ulData2 = ~ulData2;
\r
330 if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
332 xErrorDetected = pdTRUE;
\r
335 if( ulData != ulData2 )
\r
337 xErrorDetected = pdTRUE;
\r
341 /* The queue should now be empty again. */
\r
342 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
344 xErrorDetected = pdTRUE;
\r
347 #if configUSE_PREEMPTION == 0
\r
352 /* Our queue is empty once more, add 10, 11 to the back. */
\r
354 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
\r
356 xErrorDetected = pdTRUE;
\r
359 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
\r
361 xErrorDetected = pdTRUE;
\r
364 if( uxQueueMessagesWaiting( xQueue ) != 2 )
\r
366 xErrorDetected = pdTRUE;
\r
369 /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
\r
371 for( ulData = 9; ulData >= 7; ulData-- )
\r
373 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
375 xErrorDetected = pdTRUE;
\r
379 /* Now check that the queue is full, and that receiving data provides
\r
380 the expected sequence of 7, 8, 9, 10, 11. */
\r
381 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
383 xErrorDetected = pdTRUE;
\r
386 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
388 xErrorDetected = pdTRUE;
\r
391 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
393 xErrorDetected = pdTRUE;
\r
396 #if configUSE_PREEMPTION == 0
\r
400 /* Check the data we read out is in the expected order. */
\r
401 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
\r
403 if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
405 xErrorDetected = pdTRUE;
\r
408 if( ulData != ulData2 )
\r
410 xErrorDetected = pdTRUE;
\r
414 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
416 xErrorDetected = pdTRUE;
\r
422 /*-----------------------------------------------------------*/
\r
424 static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
\r
426 /* Take the mutex. It should be available now. */
\r
427 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
429 xErrorDetected = pdTRUE;
\r
432 /* Set the guarded variable to a known start value. */
\r
433 ulGuardedVariable = 0;
\r
435 /* This task's priority should be as per that assigned when the task was
\r
437 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
439 xErrorDetected = pdTRUE;
\r
442 /* Now unsuspend the high priority task. This will attempt to take the
\r
443 mutex, and block when it finds it cannot obtain it. */
\r
444 vTaskResume( xHighPriorityMutexTask );
\r
446 #if configUSE_PREEMPTION == 0
\r
450 /* Ensure the task is reporting its priority as blocked and not
\r
451 suspended (as it would have done in versions up to V7.5.3). */
\r
452 #if( INCLUDE_eTaskGetState == 1 )
\r
454 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
\r
456 #endif /* INCLUDE_eTaskGetState */
\r
458 /* The priority of the high priority task should now have been inherited
\r
459 as by now it will have attempted to get the mutex. */
\r
460 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
462 xErrorDetected = pdTRUE;
\r
465 /* Attempt to set the priority of this task to the test priority -
\r
466 between the idle priority and the medium/high test priorities, but the
\r
467 actual priority should remain at the high priority. */
\r
468 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
\r
469 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
471 xErrorDetected = pdTRUE;
\r
474 /* Now unsuspend the medium priority task. This should not run as the
\r
475 inherited priority of this task is above that of the medium priority
\r
477 vTaskResume( xMediumPriorityMutexTask );
\r
479 /* If the medium priority task did run then it will have incremented the
\r
480 guarded variable. */
\r
481 if( ulGuardedVariable != 0 )
\r
483 xErrorDetected = pdTRUE;
\r
486 /* Take the local mutex too, so two mutexes are now held. */
\r
487 if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
\r
489 xErrorDetected = pdTRUE;
\r
492 /* When the semaphore is given back the priority of this task should not
\r
493 yet be disinherited because the local mutex is still held. This is a
\r
494 simplification to allow FreeRTOS to be integrated with middleware that
\r
495 attempts to hold multiple mutexes without bloating the code with complex
\r
496 algorithms. It is possible that the high priority mutex task will
\r
497 execute as it shares a priority with this task. */
\r
498 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
500 xErrorDetected = pdTRUE;
\r
503 #if configUSE_PREEMPTION == 0
\r
507 /* The guarded variable is only incremented by the medium priority task,
\r
508 which still should not have executed as this task should remain at the
\r
509 higher priority, ensure this is the case. */
\r
510 if( ulGuardedVariable != 0 )
\r
512 xErrorDetected = pdTRUE;
\r
515 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
517 xErrorDetected = pdTRUE;
\r
520 /* Now also give back the local mutex, taking the held count back to 0.
\r
521 This time the priority of this task should be disinherited back to the
\r
522 priority to which it was set while the mutex was held. This means
\r
523 the medium priority task should execute and increment the guarded
\r
524 variable. When this task next runs both the high and medium priority
\r
525 tasks will have been suspended again. */
\r
526 if( xSemaphoreGive( xLocalMutex ) != pdPASS )
\r
528 xErrorDetected = pdTRUE;
\r
531 #if configUSE_PREEMPTION == 0
\r
535 /* Check the guarded variable did indeed increment... */
\r
536 if( ulGuardedVariable != 1 )
\r
538 xErrorDetected = pdTRUE;
\r
541 /* ... and that the priority of this task has been disinherited to
\r
542 genqMUTEX_TEST_PRIORITY. */
\r
543 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
\r
545 xErrorDetected = pdTRUE;
\r
548 /* Set the priority of this task back to its original value, ready for
\r
549 the next loop around this test. */
\r
550 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
\r
552 /*-----------------------------------------------------------*/
\r
554 static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
\r
556 /* Take the mutex. It should be available now. */
\r
557 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
559 xErrorDetected = pdTRUE;
\r
562 /* Set the guarded variable to a known start value. */
\r
563 ulGuardedVariable = 0;
\r
565 /* This task's priority should be as per that assigned when the task was
\r
567 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
569 xErrorDetected = pdTRUE;
\r
572 /* Now unsuspend the high priority task. This will attempt to take the
\r
573 mutex, and block when it finds it cannot obtain it. */
\r
574 vTaskResume( xHighPriorityMutexTask );
\r
576 #if configUSE_PREEMPTION == 0
\r
580 /* Ensure the task is reporting its priority as blocked and not
\r
581 suspended (as it would have done in versions up to V7.5.3). */
\r
582 #if( INCLUDE_eTaskGetState == 1 )
\r
584 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
\r
586 #endif /* INCLUDE_eTaskGetState */
\r
588 /* The priority of the high priority task should now have been inherited
\r
589 as by now it will have attempted to get the mutex. */
\r
590 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
592 xErrorDetected = pdTRUE;
\r
595 /* Now unsuspend the medium priority task. This should not run as the
\r
596 inherited priority of this task is above that of the medium priority
\r
598 vTaskResume( xMediumPriorityMutexTask );
\r
600 /* If the medium priority task did run then it will have incremented the
\r
601 guarded variable. */
\r
602 if( ulGuardedVariable != 0 )
\r
604 xErrorDetected = pdTRUE;
\r
607 /* Take the local mutex too, so two mutexes are now held. */
\r
608 if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
\r
610 xErrorDetected = pdTRUE;
\r
613 /* When the local semaphore is given back the priority of this task should
\r
614 not yet be disinherited because the shared mutex is still held. This is a
\r
615 simplification to allow FreeRTOS to be integrated with middleware that
\r
616 attempts to hold multiple mutexes without bloating the code with complex
\r
617 algorithms. It is possible that the high priority mutex task will
\r
618 execute as it shares a priority with this task. */
\r
619 if( xSemaphoreGive( xLocalMutex ) != pdPASS )
\r
621 xErrorDetected = pdTRUE;
\r
624 #if configUSE_PREEMPTION == 0
\r
628 /* The guarded variable is only incremented by the medium priority task,
\r
629 which still should not have executed as this task should remain at the
\r
630 higher priority, ensure this is the case. */
\r
631 if( ulGuardedVariable != 0 )
\r
633 xErrorDetected = pdTRUE;
\r
636 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
638 xErrorDetected = pdTRUE;
\r
641 /* Now also give back the shared mutex, taking the held count back to 0.
\r
642 This time the priority of this task should be disinherited back to the
\r
643 priority at which it was created. This means the medium priority task
\r
644 should execute and increment the guarded variable. When this task next runs
\r
645 both the high and medium priority tasks will have been suspended again. */
\r
646 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
648 xErrorDetected = pdTRUE;
\r
651 #if configUSE_PREEMPTION == 0
\r
655 /* Check the guarded variable did indeed increment... */
\r
656 if( ulGuardedVariable != 1 )
\r
658 xErrorDetected = pdTRUE;
\r
661 /* ... and that the priority of this task has been disinherited to
\r
662 genqMUTEX_LOW_PRIORITY. */
\r
663 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
665 xErrorDetected = pdTRUE;
\r
668 /*-----------------------------------------------------------*/
\r
670 static void prvLowPriorityMutexTask( void *pvParameters )
\r
672 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
\r
675 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
677 const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
\r
679 /* Queue a message for printing to say the task has started. */
\r
680 vPrintDisplayMessage( &pcTaskStartMsg );
\r
683 /* The local mutex is used to check the 'mutexs held' count. */
\r
684 xLocalMutex = xSemaphoreCreateMutex();
\r
685 configASSERT( xLocalMutex );
\r
689 /* The first tests exercise the priority inheritance when two mutexes
\r
690 are taken then returned in a different order to which they were
\r
692 prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );
\r
694 /* Just to show this task is still running. */
\r
697 #if configUSE_PREEMPTION == 0
\r
701 /* The second tests exercise the priority inheritance when two mutexes
\r
702 are taken then returned in the same order in which they were taken. */
\r
703 prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );
\r
705 /* Just to show this task is still running. */
\r
708 #if configUSE_PREEMPTION == 0
\r
713 /*-----------------------------------------------------------*/
\r
715 static void prvMediumPriorityMutexTask( void *pvParameters )
\r
717 ( void ) pvParameters;
\r
721 /* The medium priority task starts by suspending itself. The low
\r
722 priority task will unsuspend this task when required. */
\r
723 vTaskSuspend( NULL );
\r
725 /* When this task unsuspends all it does is increment the guarded
\r
726 variable, this is so the low priority task knows that it has
\r
728 ulGuardedVariable++;
\r
731 /*-----------------------------------------------------------*/
\r
733 static void prvHighPriorityMutexTask( void *pvParameters )
\r
735 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
\r
739 /* The high priority task starts by suspending itself. The low
\r
740 priority task will unsuspend this task when required. */
\r
741 vTaskSuspend( NULL );
\r
743 /* When this task unsuspends all it does is attempt to obtain
\r
744 the mutex. It should find the mutex is not available so a
\r
745 block time is specified. */
\r
746 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
\r
748 xErrorDetected = pdTRUE;
\r
751 /* When the mutex is eventually obtained it is just given back before
\r
752 returning to suspend ready for the next cycle. */
\r
753 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
755 xErrorDetected = pdTRUE;
\r
759 /*-----------------------------------------------------------*/
\r
762 /* This is called to check that all the created tasks are still running. */
\r
763 BaseType_t xAreGenericQueueTasksStillRunning( void )
\r
765 static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
\r
767 /* If the demo task is still running then we expect the loop counters to
\r
768 have incremented since this function was last called. */
\r
769 if( ulLastLoopCounter == ulLoopCounter )
\r
771 xErrorDetected = pdTRUE;
\r
774 if( ulLastLoopCounter2 == ulLoopCounter2 )
\r
776 xErrorDetected = pdTRUE;
\r
779 ulLastLoopCounter = ulLoopCounter;
\r
780 ulLastLoopCounter2 = ulLoopCounter2;
\r
782 /* Errors detected in the task itself will have latched xErrorDetected
\r
785 return ( BaseType_t ) !xErrorDetected;
\r