2 FreeRTOS V8.2.0rc1 - Copyright (C) 2014 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 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
14 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
15 >>! obliged to provide the source code for proprietary components !<<
\r
16 >>! outside of the FreeRTOS kernel. !<<
\r
18 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
20 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
21 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * Having a problem? Start by reading the FAQ "My application does *
\r
28 * not run, what could be wrong?". Have you defined configASSERT()? *
\r
30 * http://www.FreeRTOS.org/FAQHelp.html *
\r
32 ***************************************************************************
\r
34 ***************************************************************************
\r
36 * FreeRTOS provides completely free yet professionally developed, *
\r
37 * robust, strictly quality controlled, supported, and cross *
\r
38 * platform software that is more than just the market leader, it *
\r
39 * is the industry's de facto standard. *
\r
41 * Help yourself get started quickly while simultaneously helping *
\r
42 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
43 * tutorial book, reference manual, or both: *
\r
44 * http://www.FreeRTOS.org/Documentation *
\r
46 ***************************************************************************
\r
48 ***************************************************************************
\r
50 * Investing in training allows your team to be as productive as *
\r
51 * possible as early as possible, lowering your overall development *
\r
52 * cost, and enabling you to bring a more robust product to market *
\r
53 * earlier than would otherwise be possible. Richard Barry is both *
\r
54 * the architect and key author of FreeRTOS, and so also the world's *
\r
55 * leading authority on what is the world's most popular real time *
\r
56 * kernel for deeply embedded MCU designs. Obtaining your training *
\r
57 * from Richard ensures your team will gain directly from his in-depth *
\r
58 * product knowledge and years of usage experience. Contact Real Time *
\r
59 * Engineers Ltd to enquire about the FreeRTOS Masterclass, presented *
\r
60 * by Richard Barry: http://www.FreeRTOS.org/contact
\r
62 ***************************************************************************
\r
64 ***************************************************************************
\r
66 * You are receiving this top quality software for free. Please play *
\r
67 * fair and reciprocate by reporting any suspected issues and *
\r
68 * participating in the community forum: *
\r
69 * http://www.FreeRTOS.org/support *
\r
73 ***************************************************************************
\r
75 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
76 license and Real Time Engineers Ltd. contact details.
\r
78 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
79 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
80 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
82 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
83 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
85 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
86 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
87 licenses offer ticketed support, indemnification and commercial middleware.
\r
89 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
90 engineered and independently SIL3 certified version for use in safety and
\r
91 mission critical applications that require provable dependability.
\r
98 * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
\r
99 * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
\r
102 * See the comments above the prvSendFrontAndBackTest() and
\r
103 * prvLowPriorityMutexTask() prototypes below for more information.
\r
107 #include <stdlib.h>
\r
109 /* Scheduler include files. */
\r
110 #include "FreeRTOS.h"
\r
113 #include "semphr.h"
\r
115 /* Demo program include files. */
\r
116 #include "GenQTest.h"
\r
118 #define genqQUEUE_LENGTH ( 5 )
\r
119 #define intsemNO_BLOCK ( 0 )
\r
121 #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
\r
122 #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
\r
123 #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
\r
124 #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
\r
126 /*-----------------------------------------------------------*/
\r
129 * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
\r
130 * macros by using both to fill a queue, then reading from the queue to
\r
131 * check the resultant queue order is as expected. Queue data is also
\r
134 static void prvSendFrontAndBackTest( void *pvParameters );
\r
137 * The following three tasks are used to demonstrate the mutex behaviour.
\r
138 * Each task is given a different priority to demonstrate the priority
\r
139 * inheritance mechanism.
\r
141 * The low priority task obtains a mutex. After this a high priority task
\r
142 * attempts to obtain the same mutex, causing its priority to be inherited
\r
143 * by the low priority task. The task with the inherited high priority then
\r
144 * resumes a medium priority task to ensure it is not blocked by the medium
\r
145 * priority task while it holds the inherited high priority. Once the mutex
\r
146 * is returned the task with the inherited priority returns to its original
\r
147 * low priority, and is therefore immediately preempted by first the high
\r
148 * priority task and then the medium prioroity task before it can continue.
\r
150 static void prvLowPriorityMutexTask( void *pvParameters );
\r
151 static void prvMediumPriorityMutexTask( void *pvParameters );
\r
152 static void prvHighPriorityMutexTask( void *pvParameters );
\r
154 /*-----------------------------------------------------------*/
\r
156 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
\r
157 detected in any of the tasks. */
\r
158 static volatile BaseType_t xErrorDetected = pdFALSE;
\r
160 /* Counters that are incremented on each cycle of a test. This is used to
\r
161 detect a stalled task - a test that is no longer running. */
\r
162 static volatile uint32_t ulLoopCounter = 0;
\r
163 static volatile uint32_t ulLoopCounter2 = 0;
\r
165 /* The variable that is guarded by the mutex in the mutex demo tasks. */
\r
166 static volatile uint32_t ulGuardedVariable = 0;
\r
168 /* Handles used in the mutext test to suspend and resume the high and medium
\r
169 priority mutex test tasks. */
\r
170 static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
\r
172 /*-----------------------------------------------------------*/
\r
174 void vStartGenericQueueTasks( UBaseType_t uxPriority )
\r
176 QueueHandle_t xQueue;
\r
177 SemaphoreHandle_t xMutex;
\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
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
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
197 /* Create the mutex used by the prvMutexTest task. */
\r
198 xMutex = xSemaphoreCreateMutex();
\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
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
215 /*-----------------------------------------------------------*/
\r
217 static void prvSendFrontAndBackTest( void *pvParameters )
\r
219 uint32_t ulData, ulData2;
\r
220 QueueHandle_t xQueue;
\r
223 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
225 const char * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
\r
227 /* Queue a message for printing to say the task has started. */
\r
228 vPrintDisplayMessage( &pcTaskStartMsg );
\r
231 xQueue = ( QueueHandle_t ) pvParameters;
\r
235 /* The queue is empty, so sending an item to the back of the queue
\r
236 should have the same efect as sending it to the front of the queue.
\r
238 First send to the front and check everything is as expected. */
\r
239 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
\r
241 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
243 xErrorDetected = pdTRUE;
\r
246 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
248 xErrorDetected = pdTRUE;
\r
251 /* The data we sent to the queue should equal the data we just received
\r
253 if( ulLoopCounter != ulData )
\r
255 xErrorDetected = pdTRUE;
\r
258 /* Then do the same, sending the data to the back, checking everything
\r
260 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
262 xErrorDetected = pdTRUE;
\r
265 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, intsemNO_BLOCK );
\r
267 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
269 xErrorDetected = pdTRUE;
\r
272 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
274 xErrorDetected = pdTRUE;
\r
277 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
279 xErrorDetected = pdTRUE;
\r
282 /* The data we sent to the queue should equal the data we just received
\r
284 if( ulLoopCounter != ulData )
\r
286 xErrorDetected = pdTRUE;
\r
289 #if configUSE_PREEMPTION == 0
\r
295 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
\r
296 for( ulData = 2; ulData < 5; ulData++ )
\r
298 xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
301 /* Now the order in the queue should be 2, 3, 4, with 2 being the first
\r
302 thing to be read out. Now add 1 then 0 to the front of the queue. */
\r
303 if( uxQueueMessagesWaiting( xQueue ) != 3 )
\r
305 xErrorDetected = pdTRUE;
\r
308 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
310 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
312 /* Now the queue should be full, and when we read the data out we
\r
313 should receive 0, 1, 2, 3, 4. */
\r
314 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
316 xErrorDetected = pdTRUE;
\r
319 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
321 xErrorDetected = pdTRUE;
\r
324 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
326 xErrorDetected = pdTRUE;
\r
329 #if configUSE_PREEMPTION == 0
\r
333 /* Check the data we read out is in the expected order. */
\r
334 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
\r
336 /* Try peeking the data first. */
\r
337 if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
339 xErrorDetected = pdTRUE;
\r
342 if( ulData != ulData2 )
\r
344 xErrorDetected = pdTRUE;
\r
348 /* Now try receiving the data for real. The value should be the
\r
349 same. Clobber the value first so we know we really received it. */
\r
350 ulData2 = ~ulData2;
\r
351 if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
353 xErrorDetected = pdTRUE;
\r
356 if( ulData != ulData2 )
\r
358 xErrorDetected = pdTRUE;
\r
362 /* The queue should now be empty again. */
\r
363 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
365 xErrorDetected = pdTRUE;
\r
368 #if configUSE_PREEMPTION == 0
\r
373 /* Our queue is empty once more, add 10, 11 to the back. */
\r
375 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
\r
377 xErrorDetected = pdTRUE;
\r
380 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
\r
382 xErrorDetected = pdTRUE;
\r
385 if( uxQueueMessagesWaiting( xQueue ) != 2 )
\r
387 xErrorDetected = pdTRUE;
\r
390 /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
\r
392 for( ulData = 9; ulData >= 7; ulData-- )
\r
394 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
396 xErrorDetected = pdTRUE;
\r
400 /* Now check that the queue is full, and that receiving data provides
\r
401 the expected sequence of 7, 8, 9, 10, 11. */
\r
402 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
404 xErrorDetected = pdTRUE;
\r
407 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
409 xErrorDetected = pdTRUE;
\r
412 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
414 xErrorDetected = pdTRUE;
\r
417 #if configUSE_PREEMPTION == 0
\r
421 /* Check the data we read out is in the expected order. */
\r
422 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
\r
424 if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
426 xErrorDetected = pdTRUE;
\r
429 if( ulData != ulData2 )
\r
431 xErrorDetected = pdTRUE;
\r
435 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
437 xErrorDetected = pdTRUE;
\r
443 /*-----------------------------------------------------------*/
\r
445 static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
\r
447 /* Take the mutex. It should be available now. */
\r
448 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
450 xErrorDetected = pdTRUE;
\r
453 /* Set the guarded variable to a known start value. */
\r
454 ulGuardedVariable = 0;
\r
456 /* This task's priority should be as per that assigned when the task was
\r
458 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
460 xErrorDetected = pdTRUE;
\r
463 /* Now unsuspend the high priority task. This will attempt to take the
\r
464 mutex, and block when it finds it cannot obtain it. */
\r
465 vTaskResume( xHighPriorityMutexTask );
\r
467 #if configUSE_PREEMPTION == 0
\r
471 /* Ensure the task is reporting its priority as blocked and not
\r
472 suspended (as it would have done in versions up to V7.5.3). */
\r
473 #if( INCLUDE_eTaskGetState == 1 )
\r
475 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
\r
477 #endif /* INCLUDE_eTaskGetState */
\r
479 /* The priority of the high priority task should now have been inherited
\r
480 as by now it will have attempted to get the mutex. */
\r
481 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
483 xErrorDetected = pdTRUE;
\r
486 /* Attempt to set the priority of this task to the test priority -
\r
487 between the idle priority and the medium/high test priorities, but the
\r
488 actual priority should remain at the high priority. */
\r
489 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
\r
490 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
492 xErrorDetected = pdTRUE;
\r
495 /* Now unsuspend the medium priority task. This should not run as the
\r
496 inherited priority of this task is above that of the medium priority
\r
498 vTaskResume( xMediumPriorityMutexTask );
\r
500 /* If the medium priority task did run then it will have incremented the
\r
501 guarded variable. */
\r
502 if( ulGuardedVariable != 0 )
\r
504 xErrorDetected = pdTRUE;
\r
507 /* Take the local mutex too, so two mutexes are now held. */
\r
508 if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
\r
510 xErrorDetected = pdTRUE;
\r
513 /* When the semaphore is given back the priority of this task should not
\r
514 yet be disinherited because the local mutex is still held. This is a
\r
515 simplification to allow FreeRTOS to be integrated with middleware that
\r
516 attempts to hold multiple mutexes without bloating the code with complex
\r
517 algorithms. It is possible that the high priority mutex task will
\r
518 execute as it shares a priority with this task. */
\r
519 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
521 xErrorDetected = pdTRUE;
\r
524 #if configUSE_PREEMPTION == 0
\r
528 /* The guarded variable is only incremented by the medium priority task,
\r
529 which still should not have executed as this task should remain at the
\r
530 higher priority, ensure this is the case. */
\r
531 if( ulGuardedVariable != 0 )
\r
533 xErrorDetected = pdTRUE;
\r
536 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
538 xErrorDetected = pdTRUE;
\r
541 /* Now also give back the local mutex, taking the held count back to 0.
\r
542 This time the priority of this task should be disinherited back to the
\r
543 priority to which it was set while the mutex was held. This means
\r
544 the medium priority task should execute and increment the guarded
\r
545 variable. When this task next runs both the high and medium priority
\r
546 tasks will have been suspended again. */
\r
547 if( xSemaphoreGive( xLocalMutex ) != pdPASS )
\r
549 xErrorDetected = pdTRUE;
\r
552 #if configUSE_PREEMPTION == 0
\r
556 /* Check the guarded variable did indeed increment... */
\r
557 if( ulGuardedVariable != 1 )
\r
559 xErrorDetected = pdTRUE;
\r
562 /* ... and that the priority of this task has been disinherited to
\r
563 genqMUTEX_TEST_PRIORITY. */
\r
564 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
\r
566 xErrorDetected = pdTRUE;
\r
569 /* Set the priority of this task back to its original value, ready for
\r
570 the next loop around this test. */
\r
571 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
\r
573 /*-----------------------------------------------------------*/
\r
575 static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
\r
577 /* Take the mutex. It should be available now. */
\r
578 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
580 xErrorDetected = pdTRUE;
\r
583 /* Set the guarded variable to a known start value. */
\r
584 ulGuardedVariable = 0;
\r
586 /* This task's priority should be as per that assigned when the task was
\r
588 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
590 xErrorDetected = pdTRUE;
\r
593 /* Now unsuspend the high priority task. This will attempt to take the
\r
594 mutex, and block when it finds it cannot obtain it. */
\r
595 vTaskResume( xHighPriorityMutexTask );
\r
597 #if configUSE_PREEMPTION == 0
\r
601 /* Ensure the task is reporting its priority as blocked and not
\r
602 suspended (as it would have done in versions up to V7.5.3). */
\r
603 #if( INCLUDE_eTaskGetState == 1 )
\r
605 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
\r
607 #endif /* INCLUDE_eTaskGetState */
\r
609 /* The priority of the high priority task should now have been inherited
\r
610 as by now it will have attempted to get the mutex. */
\r
611 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
613 xErrorDetected = pdTRUE;
\r
616 /* Now unsuspend the medium priority task. This should not run as the
\r
617 inherited priority of this task is above that of the medium priority
\r
619 vTaskResume( xMediumPriorityMutexTask );
\r
621 /* If the medium priority task did run then it will have incremented the
\r
622 guarded variable. */
\r
623 if( ulGuardedVariable != 0 )
\r
625 xErrorDetected = pdTRUE;
\r
628 /* Take the local mutex too, so two mutexes are now held. */
\r
629 if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
\r
631 xErrorDetected = pdTRUE;
\r
634 /* When the local semaphore is given back the priority of this task should
\r
635 not yet be disinherited because the shared mutex is still held. This is a
\r
636 simplification to allow FreeRTOS to be integrated with middleware that
\r
637 attempts to hold multiple mutexes without bloating the code with complex
\r
638 algorithms. It is possible that the high priority mutex task will
\r
639 execute as it shares a priority with this task. */
\r
640 if( xSemaphoreGive( xLocalMutex ) != pdPASS )
\r
642 xErrorDetected = pdTRUE;
\r
645 #if configUSE_PREEMPTION == 0
\r
649 /* The guarded variable is only incremented by the medium priority task,
\r
650 which still should not have executed as this task should remain at the
\r
651 higher priority, ensure this is the case. */
\r
652 if( ulGuardedVariable != 0 )
\r
654 xErrorDetected = pdTRUE;
\r
657 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
659 xErrorDetected = pdTRUE;
\r
662 /* Now also give back the shared mutex, taking the held count back to 0.
\r
663 This time the priority of this task should be disinherited back to the
\r
664 priority at which it was created. This means the medium priority task
\r
665 should execute and increment the guarded variable. When this task next runs
\r
666 both the high and medium priority tasks will have been suspended again. */
\r
667 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
669 xErrorDetected = pdTRUE;
\r
672 #if configUSE_PREEMPTION == 0
\r
676 /* Check the guarded variable did indeed increment... */
\r
677 if( ulGuardedVariable != 1 )
\r
679 xErrorDetected = pdTRUE;
\r
682 /* ... and that the priority of this task has been disinherited to
\r
683 genqMUTEX_LOW_PRIORITY. */
\r
684 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
686 xErrorDetected = pdTRUE;
\r
689 /*-----------------------------------------------------------*/
\r
691 static void prvLowPriorityMutexTask( void *pvParameters )
\r
693 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
\r
696 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
698 const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
\r
700 /* Queue a message for printing to say the task has started. */
\r
701 vPrintDisplayMessage( &pcTaskStartMsg );
\r
704 /* The local mutex is used to check the 'mutexs held' count. */
\r
705 xLocalMutex = xSemaphoreCreateMutex();
\r
706 configASSERT( xLocalMutex );
\r
710 /* The first tests exercise the priority inheritance when two mutexes
\r
711 are taken then returned in a different order to which they were
\r
713 prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );
\r
715 /* Just to show this task is still running. */
\r
718 #if configUSE_PREEMPTION == 0
\r
722 /* The second tests exercise the priority inheritance when two mutexes
\r
723 are taken then returned in the same order in which they were taken. */
\r
724 prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );
\r
726 /* Just to show this task is still running. */
\r
729 #if configUSE_PREEMPTION == 0
\r
734 /*-----------------------------------------------------------*/
\r
736 static void prvMediumPriorityMutexTask( void *pvParameters )
\r
738 ( void ) pvParameters;
\r
742 /* The medium priority task starts by suspending itself. The low
\r
743 priority task will unsuspend this task when required. */
\r
744 vTaskSuspend( NULL );
\r
746 /* When this task unsuspends all it does is increment the guarded
\r
747 variable, this is so the low priority task knows that it has
\r
749 ulGuardedVariable++;
\r
752 /*-----------------------------------------------------------*/
\r
754 static void prvHighPriorityMutexTask( void *pvParameters )
\r
756 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
\r
760 /* The high priority task starts by suspending itself. The low
\r
761 priority task will unsuspend this task when required. */
\r
762 vTaskSuspend( NULL );
\r
764 /* When this task unsuspends all it does is attempt to obtain
\r
765 the mutex. It should find the mutex is not available so a
\r
766 block time is specified. */
\r
767 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
\r
769 xErrorDetected = pdTRUE;
\r
772 /* When the mutex is eventually obtained it is just given back before
\r
773 returning to suspend ready for the next cycle. */
\r
774 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
776 xErrorDetected = pdTRUE;
\r
780 /*-----------------------------------------------------------*/
\r
783 /* This is called to check that all the created tasks are still running. */
\r
784 BaseType_t xAreGenericQueueTasksStillRunning( void )
\r
786 static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
\r
788 /* If the demo task is still running then we expect the loop counters to
\r
789 have incremented since this function was last called. */
\r
790 if( ulLastLoopCounter == ulLoopCounter )
\r
792 xErrorDetected = pdTRUE;
\r
795 if( ulLastLoopCounter2 == ulLoopCounter2 )
\r
797 xErrorDetected = pdTRUE;
\r
800 ulLastLoopCounter = ulLoopCounter;
\r
801 ulLastLoopCounter2 = ulLoopCounter2;
\r
803 /* Errors detected in the task itself will have latched xErrorDetected
\r
806 return ( BaseType_t ) !xErrorDetected;
\r