2 * FreeRTOS Kernel V10.1.0
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
30 * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
\r
31 * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
\r
34 * See the comments above the prvSendFrontAndBackTest() and
\r
35 * prvLowPriorityMutexTask() prototypes below for more information.
\r
38 /* Standard includes. */
\r
41 /* Scheduler include files. */
\r
42 #include "FreeRTOS.h"
\r
47 /* Demo program include files. */
\r
48 #include "GenQTest.h"
\r
50 #define genqQUEUE_LENGTH ( 5 )
\r
51 #define intsemNO_BLOCK ( 0 )
\r
52 #define genqSHORT_BLOCK ( pdMS_TO_TICKS( 2 ) )
\r
54 #define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
\r
55 #define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
\r
56 #define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
\r
57 #define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
\r
59 /*-----------------------------------------------------------*/
\r
62 * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
\r
63 * macros by using both to fill a queue, then reading from the queue to
\r
64 * check the resultant queue order is as expected. Queue data is also
\r
67 static void prvSendFrontAndBackTest( void *pvParameters );
\r
70 * The following three tasks are used to demonstrate the mutex behaviour.
\r
71 * Each task is given a different priority to demonstrate the priority
\r
72 * inheritance mechanism.
\r
74 * The low priority task obtains a mutex. After this a high priority task
\r
75 * attempts to obtain the same mutex, causing its priority to be inherited
\r
76 * by the low priority task. The task with the inherited high priority then
\r
77 * resumes a medium priority task to ensure it is not blocked by the medium
\r
78 * priority task while it holds the inherited high priority. Once the mutex
\r
79 * is returned the task with the inherited priority returns to its original
\r
80 * low priority, and is therefore immediately preempted by first the high
\r
81 * priority task and then the medium priority task before it can continue.
\r
83 static void prvLowPriorityMutexTask( void *pvParameters );
\r
84 static void prvMediumPriorityMutexTask( void *pvParameters );
\r
85 static void prvHighPriorityMutexTask( void *pvParameters );
\r
88 * Tests the behaviour when a low priority task inherits the priority of a
\r
89 * higher priority task when taking two mutexes, and returns the mutexes in
\r
90 * first the same order as the two mutexes were obtained, and second the
\r
91 * opposite order as the two mutexes were obtained.
\r
93 static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );
\r
94 static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex );
\r
96 #if( INCLUDE_xTaskAbortDelay == 1 )
\r
98 #if( configUSE_PREEMPTION == 0 )
\r
99 #error The additional tests included when INCLUDE_xTaskAbortDelay is 1 expect preemption to be used.
\r
102 /* Tests the behaviour when a low priority task inherits the priority of a
\r
103 high priority task only for the high priority task to timeout before
\r
104 obtaining the mutex. */
\r
105 static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex );
\r
108 /*-----------------------------------------------------------*/
\r
110 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
\r
111 detected in any of the tasks. */
\r
112 static volatile BaseType_t xErrorDetected = pdFALSE;
\r
114 /* Counters that are incremented on each cycle of a test. This is used to
\r
115 detect a stalled task - a test that is no longer running. */
\r
116 static volatile uint32_t ulLoopCounter = 0;
\r
117 static volatile uint32_t ulLoopCounter2 = 0;
\r
119 /* The variable that is guarded by the mutex in the mutex demo tasks. */
\r
120 static volatile uint32_t ulGuardedVariable = 0;
\r
122 /* Handles used in the mutex test to suspend and resume the high and medium
\r
123 priority mutex test tasks. */
\r
124 static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
\r
126 /* If INCLUDE_xTaskAbortDelay is 1 additional tests are performed, requiring an
\r
127 additional task. */
\r
128 #if( INCLUDE_xTaskAbortDelay == 1 )
\r
129 static TaskHandle_t xSecondMediumPriorityMutexTask;
\r
132 /* Lets the high priority semaphore task know that its wait for the semaphore
\r
133 was aborted, in which case not being able to obtain the semaphore is not to be
\r
134 considered an error. */
\r
135 static volatile BaseType_t xBlockWasAborted = pdFALSE;
\r
137 /*-----------------------------------------------------------*/
\r
139 void vStartGenericQueueTasks( UBaseType_t uxPriority )
\r
141 QueueHandle_t xQueue;
\r
142 SemaphoreHandle_t xMutex;
\r
144 /* Create the queue that we are going to use for the
\r
145 prvSendFrontAndBackTest demo. */
\r
146 xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );
\r
148 if( xQueue != NULL )
\r
150 /* vQueueAddToRegistry() adds the queue to the queue registry, if one
\r
151 is in use. The queue registry is provided as a means for kernel aware
\r
152 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
153 is not being used. The call to vQueueAddToRegistry() will be removed
\r
154 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
155 defined to be less than 1. */
\r
156 vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );
\r
158 /* Create the demo task and pass it the queue just created. We are
\r
159 passing the queue handle by value so it does not matter that it is
\r
160 declared on the stack here. */
\r
161 xTaskCreate( prvSendFrontAndBackTest, "GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
\r
164 /* Create the mutex used by the prvMutexTest task. */
\r
165 xMutex = xSemaphoreCreateMutex();
\r
167 if( xMutex != NULL )
\r
169 /* vQueueAddToRegistry() adds the mutex to the registry, if one is
\r
170 in use. The registry is provided as a means for kernel aware
\r
171 debuggers to locate mutexes and has no purpose if a kernel aware
\r
172 debugger is not being used. The call to vQueueAddToRegistry() will be
\r
173 removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
\r
174 defined or is defined to be less than 1. */
\r
175 vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );
\r
177 /* Create the mutex demo tasks and pass it the mutex just created. We
\r
178 are passing the mutex handle by value so it does not matter that it is
\r
179 declared on the stack here. */
\r
180 xTaskCreate( prvLowPriorityMutexTask, "MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
\r
181 xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
\r
182 xTaskCreate( prvHighPriorityMutexTask, "MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
\r
184 /* If INCLUDE_xTaskAbortDelay is set then additional tests are performed,
\r
185 requiring two instances of prvHighPriorityMutexTask(). */
\r
186 #if( INCLUDE_xTaskAbortDelay == 1 )
\r
188 xTaskCreate( prvHighPriorityMutexTask, "MuHigh2", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_MEDIUM_PRIORITY, &xSecondMediumPriorityMutexTask );
\r
190 #endif /* INCLUDE_xTaskAbortDelay */
\r
193 /*-----------------------------------------------------------*/
\r
195 static void prvSendFrontAndBackTest( void *pvParameters )
\r
197 uint32_t ulData, ulData2, ulLoopCounterSnapshot;
\r
198 QueueHandle_t xQueue;
\r
201 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
203 const char * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
\r
205 /* Queue a message for printing to say the task has started. */
\r
206 vPrintDisplayMessage( &pcTaskStartMsg );
\r
209 xQueue = ( QueueHandle_t ) pvParameters;
\r
213 /* The queue is empty, so sending an item to the back of the queue
\r
214 should have the same efect as sending it to the front of the queue.
\r
216 First send to the front and check everything is as expected. */
\r
217 ulLoopCounterSnapshot = ulLoopCounter;
\r
218 xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, 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 ulLoopCounterSnapshot = ulLoopCounter;
\r
245 xQueueSendToBack( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );
\r
247 if( uxQueueMessagesWaiting( xQueue ) != 1 )
\r
249 xErrorDetected = pdTRUE;
\r
252 if( xQueueReceive( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
254 xErrorDetected = pdTRUE;
\r
257 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
259 xErrorDetected = pdTRUE;
\r
262 /* The data sent to the queue should equal the data just received from
\r
264 if( ulLoopCounter != ulData )
\r
266 xErrorDetected = pdTRUE;
\r
269 #if configUSE_PREEMPTION == 0
\r
275 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
\r
276 for( ulData = 2; ulData < 5; ulData++ )
\r
278 xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
281 /* Now the order in the queue should be 2, 3, 4, with 2 being the first
\r
282 thing to be read out. Now add 1 then 0 to the front of the queue. */
\r
283 if( uxQueueMessagesWaiting( xQueue ) != 3 )
\r
285 xErrorDetected = pdTRUE;
\r
288 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
290 xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
\r
292 /* Now the queue should be full, and when we read the data out we
\r
293 should receive 0, 1, 2, 3, 4. */
\r
294 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
296 xErrorDetected = pdTRUE;
\r
299 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
301 xErrorDetected = pdTRUE;
\r
304 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
306 xErrorDetected = pdTRUE;
\r
309 #if configUSE_PREEMPTION == 0
\r
313 /* Check the data we read out is in the expected order. */
\r
314 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
\r
316 /* Try peeking the data first. */
\r
317 if( xQueuePeek( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
319 xErrorDetected = pdTRUE;
\r
322 if( ulData != ulData2 )
\r
324 xErrorDetected = pdTRUE;
\r
328 /* Now try receiving the data for real. The value should be the
\r
329 same. Clobber the value first so we know we really received it. */
\r
330 ulData2 = ~ulData2;
\r
331 if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
333 xErrorDetected = pdTRUE;
\r
336 if( ulData != ulData2 )
\r
338 xErrorDetected = pdTRUE;
\r
342 /* The queue should now be empty again. */
\r
343 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
345 xErrorDetected = pdTRUE;
\r
348 #if configUSE_PREEMPTION == 0
\r
353 /* Our queue is empty once more, add 10, 11 to the back. */
\r
355 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
\r
357 xErrorDetected = pdTRUE;
\r
360 if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
\r
362 xErrorDetected = pdTRUE;
\r
365 if( uxQueueMessagesWaiting( xQueue ) != 2 )
\r
367 xErrorDetected = pdTRUE;
\r
370 /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
\r
372 for( ulData = 9; ulData >= 7; ulData-- )
\r
374 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
\r
376 xErrorDetected = pdTRUE;
\r
380 /* Now check that the queue is full, and that receiving data provides
\r
381 the expected sequence of 7, 8, 9, 10, 11. */
\r
382 if( uxQueueMessagesWaiting( xQueue ) != 5 )
\r
384 xErrorDetected = pdTRUE;
\r
387 if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
389 xErrorDetected = pdTRUE;
\r
392 if( xQueueSendToBack( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != errQUEUE_FULL )
\r
394 xErrorDetected = pdTRUE;
\r
397 #if configUSE_PREEMPTION == 0
\r
401 /* Check the data we read out is in the expected order. */
\r
402 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
\r
404 if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
\r
406 xErrorDetected = pdTRUE;
\r
409 if( ulData != ulData2 )
\r
411 xErrorDetected = pdTRUE;
\r
415 if( uxQueueMessagesWaiting( xQueue ) != 0 )
\r
417 xErrorDetected = pdTRUE;
\r
420 /* Increment the loop counter to indicate these tasks are still
\r
425 /*-----------------------------------------------------------*/
\r
427 #if( INCLUDE_xTaskAbortDelay == 1 )
\r
429 static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex )
\r
431 static UBaseType_t uxLoopCount = 0;
\r
433 /* The tests in this function are very similar, the slight variations
\r
434 are for code coverage purposes. */
\r
436 /* Take the mutex. It should be available now. Check before and after
\r
437 taking that the holder is reported correctly. */
\r
438 if( xSemaphoreGetMutexHolder( xMutex ) != NULL )
\r
440 xErrorDetected = pdTRUE;
\r
442 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
444 xErrorDetected = pdTRUE;
\r
446 if( xSemaphoreGetMutexHolder( xMutex ) != xTaskGetCurrentTaskHandle() )
\r
448 xErrorDetected = pdTRUE;
\r
451 /* This task's priority should be as per that assigned when the task was
\r
453 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
455 xErrorDetected = pdTRUE;
\r
458 /* Now unsuspend the high priority task. This will attempt to take the
\r
459 mutex, and block when it finds it cannot obtain it. */
\r
460 vTaskResume( xHighPriorityMutexTask );
\r
462 /* This task should now have inherited the priority of the high priority
\r
463 task as by now the high priority task will have attempted to obtain the
\r
465 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
467 xErrorDetected = pdTRUE;
\r
470 /* Unblock a second medium priority task. It too will attempt to take
\r
471 the mutex and enter the Blocked state - it won't run yet though as this
\r
472 task has inherited a priority above it. */
\r
473 vTaskResume( xSecondMediumPriorityMutexTask );
\r
475 /* This task should still have the priority of the high priority task as
\r
476 that had already been inherited as is the highest priority of the three
\r
477 tasks using the mutex. */
\r
478 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
480 xErrorDetected = pdTRUE;
\r
483 /* On some loops, block for a short while to provide additional
\r
484 code coverage. Blocking here will allow the medium priority task to
\r
485 execute and so also block on the mutex so when the high priority task
\r
486 causes this task to disinherit the high priority it is inherited down to
\r
487 the priority of the medium priority task. When there is no delay the
\r
488 medium priority task will not run until after the disinheritance, so
\r
489 this task will disinherit back to its base priority, then only up to the
\r
490 medium priority after the medium priority has executed. */
\r
491 vTaskDelay( uxLoopCount & ( UBaseType_t ) 0x07 );
\r
493 /* Now force the high priority task to unblock. It will fail to obtain
\r
494 the mutex and go back to the suspended state - allowing this task to
\r
495 execute again. xBlockWasAborted is set to pdTRUE so the higher priority
\r
496 task knows that its failure to obtain the semaphore is not an error. */
\r
497 xBlockWasAborted = pdTRUE;
\r
498 if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )
\r
500 xErrorDetected = pdTRUE;
\r
503 /* This task has inherited the priority of xHighPriorityMutexTask so
\r
504 could still be running even though xHighPriorityMutexTask is no longer
\r
505 blocked. Delay for a short while to ensure xHighPriorityMutexTask gets
\r
506 a chance to run - indicated by this task changing priority. It should
\r
507 disinherit the high priority task, but then inherit the priority of the
\r
508 medium priority task that is waiting for the same mutex. */
\r
509 while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
\r
511 /* If this task gets stuck here then the check variables will stop
\r
512 incrementing and the check task will detect the error. */
\r
513 vTaskDelay( genqSHORT_BLOCK );
\r
516 /* Now force the medium priority task to unblock. xBlockWasAborted is
\r
517 set to pdTRUE so the medium priority task knows that its failure to
\r
518 obtain the semaphore is not an error. */
\r
519 xBlockWasAborted = pdTRUE;
\r
520 if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )
\r
522 xErrorDetected = pdTRUE;
\r
525 /* This time no other tasks are waiting for the mutex, so this task
\r
526 should return to its base priority. This might not happen straight
\r
527 away as it is running at the same priority as the task it just
\r
529 while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
531 /* If this task gets stuck here then the check variables will stop
\r
532 incrementing and the check task will detect the error. */
\r
533 vTaskDelay( genqSHORT_BLOCK );
\r
536 /* Give the semaphore back ready for the next test. Check the mutex
\r
537 holder before and after using the "FromISR" version for code coverage. */
\r
538 if( xSemaphoreGetMutexHolderFromISR( xMutex ) != xTaskGetCurrentTaskHandle() )
\r
540 xErrorDetected = pdTRUE;
\r
542 xSemaphoreGive( xMutex );
\r
543 if( xSemaphoreGetMutexHolderFromISR( xMutex ) != NULL )
\r
545 xErrorDetected = pdTRUE;
\r
548 configASSERT( xErrorDetected == pdFALSE );
\r
552 /* Now do the same again, but this time unsuspend the tasks in the
\r
553 opposite order. This takes a different path though the code because
\r
554 when the high priority task has its block aborted there is already
\r
555 another task in the list of tasks waiting for the mutex, and the
\r
556 low priority task drops down to that priority, rather than dropping
\r
557 down to its base priority before inheriting the priority of the medium
\r
559 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
561 xErrorDetected = pdTRUE;
\r
564 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
566 xErrorDetected = pdTRUE;
\r
569 /* This time unsuspend the medium priority task first. This will
\r
570 attempt to take the mutex, and block when it finds it cannot obtain it. */
\r
571 vTaskResume( xSecondMediumPriorityMutexTask );
\r
573 /* This time this task should now have inherited the priority of the
\r
575 if( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
\r
577 xErrorDetected = pdTRUE;
\r
580 /* This time the high priority task in unsuspended second. */
\r
581 vTaskResume( xHighPriorityMutexTask );
\r
583 /* The high priority task should already have run, causing this task to
\r
584 inherit a priority for the second time. */
\r
585 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
587 xErrorDetected = pdTRUE;
\r
590 /* This time, when the high priority task has its delay aborted and it
\r
591 fails to obtain the mutex this task will immediately have its priority
\r
592 lowered down to that of the highest priority task waiting on the mutex,
\r
593 which is the medium priority task. */
\r
594 xBlockWasAborted = pdTRUE;
\r
595 if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )
\r
597 xErrorDetected = pdTRUE;
\r
600 while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
\r
602 /* If this task gets stuck here then the check variables will stop
\r
603 incrementing and the check task will detect the error. */
\r
604 vTaskDelay( genqSHORT_BLOCK );
\r
607 /* And finally, when the medium priority task also have its delay
\r
608 aborted there are no other tasks waiting for the mutex so this task
\r
609 returns to its base priority. */
\r
610 xBlockWasAborted = pdTRUE;
\r
611 if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )
\r
613 xErrorDetected = pdTRUE;
\r
616 while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
618 /* If this task gets stuck here then the check variables will stop
\r
619 incrementing and the check task will detect the error. */
\r
620 vTaskDelay( genqSHORT_BLOCK );
\r
623 /* Give the semaphore back ready for the next test. */
\r
624 xSemaphoreGive( xMutex );
\r
626 configASSERT( xErrorDetected == pdFALSE );
\r
628 /* uxLoopCount is used to add a variable delay, and in-so-doing provide
\r
629 additional code coverage. */
\r
633 #endif /* INCLUDE_xTaskAbortDelay == 1 */
\r
634 /*-----------------------------------------------------------*/
\r
636 static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
\r
638 /* Take the mutex. It should be available now. */
\r
639 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
641 xErrorDetected = pdTRUE;
\r
644 /* Set the guarded variable to a known start value. */
\r
645 ulGuardedVariable = 0;
\r
647 /* This task's priority should be as per that assigned when the task was
\r
649 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
651 xErrorDetected = pdTRUE;
\r
654 /* Now unsuspend the high priority task. This will attempt to take the
\r
655 mutex, and block when it finds it cannot obtain it. */
\r
656 vTaskResume( xHighPriorityMutexTask );
\r
658 #if configUSE_PREEMPTION == 0
\r
662 /* Ensure the task is reporting its priority as blocked and not
\r
663 suspended (as it would have done in versions up to V7.5.3). */
\r
664 #if( INCLUDE_eTaskGetState == 1 )
\r
666 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
\r
668 #endif /* INCLUDE_eTaskGetState */
\r
670 /* This task should now have inherited the priority of the high priority
\r
671 task as by now the high priority task will have attempted to obtain the
\r
673 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
675 xErrorDetected = pdTRUE;
\r
678 /* Attempt to set the priority of this task to the test priority -
\r
679 between the idle priority and the medium/high test priorities, but the
\r
680 actual priority should remain at the high priority. */
\r
681 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
\r
682 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
684 xErrorDetected = pdTRUE;
\r
687 /* Now unsuspend the medium priority task. This should not run as the
\r
688 inherited priority of this task is above that of the medium priority
\r
690 vTaskResume( xMediumPriorityMutexTask );
\r
692 /* If the medium priority task did run then it will have incremented the
\r
693 guarded variable. */
\r
694 if( ulGuardedVariable != 0 )
\r
696 xErrorDetected = pdTRUE;
\r
699 /* Take the local mutex too, so two mutexes are now held. */
\r
700 if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
\r
702 xErrorDetected = pdTRUE;
\r
705 /* When the semaphore is given back the priority of this task should not
\r
706 yet be disinherited because the local mutex is still held. This is a
\r
707 simplification to allow FreeRTOS to be integrated with middleware that
\r
708 attempts to hold multiple mutexes without bloating the code with complex
\r
709 algorithms. It is possible that the high priority mutex task will
\r
710 execute as it shares a priority with this task. */
\r
711 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
713 xErrorDetected = pdTRUE;
\r
716 #if configUSE_PREEMPTION == 0
\r
720 /* The guarded variable is only incremented by the medium priority task,
\r
721 which still should not have executed as this task should remain at the
\r
722 higher priority, ensure this is the case. */
\r
723 if( ulGuardedVariable != 0 )
\r
725 xErrorDetected = pdTRUE;
\r
728 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
730 xErrorDetected = pdTRUE;
\r
733 /* Now also give back the local mutex, taking the held count back to 0.
\r
734 This time the priority of this task should be disinherited back to the
\r
735 priority to which it was set while the mutex was held. This means
\r
736 the medium priority task should execute and increment the guarded
\r
737 variable. When this task next runs both the high and medium priority
\r
738 tasks will have been suspended again. */
\r
739 if( xSemaphoreGive( xLocalMutex ) != pdPASS )
\r
741 xErrorDetected = pdTRUE;
\r
744 #if configUSE_PREEMPTION == 0
\r
748 /* Check the guarded variable did indeed increment... */
\r
749 if( ulGuardedVariable != 1 )
\r
751 xErrorDetected = pdTRUE;
\r
754 /* ... and that the priority of this task has been disinherited to
\r
755 genqMUTEX_TEST_PRIORITY. */
\r
756 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
\r
758 xErrorDetected = pdTRUE;
\r
761 /* Set the priority of this task back to its original value, ready for
\r
762 the next loop around this test. */
\r
763 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
\r
765 /*-----------------------------------------------------------*/
\r
767 static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex )
\r
769 /* Take the mutex. It should be available now. */
\r
770 if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
\r
772 xErrorDetected = pdTRUE;
\r
775 /* Set the guarded variable to a known start value. */
\r
776 ulGuardedVariable = 0;
\r
778 /* This task's priority should be as per that assigned when the task was
\r
780 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
782 xErrorDetected = pdTRUE;
\r
785 /* Now unsuspend the high priority task. This will attempt to take the
\r
786 mutex, and block when it finds it cannot obtain it. */
\r
787 vTaskResume( xHighPriorityMutexTask );
\r
789 #if configUSE_PREEMPTION == 0
\r
793 /* Ensure the task is reporting its priority as blocked and not
\r
794 suspended (as it would have done in versions up to V7.5.3). */
\r
795 #if( INCLUDE_eTaskGetState == 1 )
\r
797 configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
\r
799 #endif /* INCLUDE_eTaskGetState */
\r
801 /* This task should now have inherited the priority of the high priority
\r
802 task as by now the high priority task will have attempted to obtain the
\r
804 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
806 xErrorDetected = pdTRUE;
\r
809 /* Now unsuspend the medium priority task. This should not run as the
\r
810 inherited priority of this task is above that of the medium priority
\r
812 vTaskResume( xMediumPriorityMutexTask );
\r
814 /* If the medium priority task did run then it will have incremented the
\r
815 guarded variable. */
\r
816 if( ulGuardedVariable != 0 )
\r
818 xErrorDetected = pdTRUE;
\r
821 /* Take the local mutex too, so two mutexes are now held. */
\r
822 if( xSemaphoreTake( xLocalMutex, intsemNO_BLOCK ) != pdPASS )
\r
824 xErrorDetected = pdTRUE;
\r
827 /* When the local semaphore is given back the priority of this task should
\r
828 not yet be disinherited because the shared mutex is still held. This is a
\r
829 simplification to allow FreeRTOS to be integrated with middleware that
\r
830 attempts to hold multiple mutexes without bloating the code with complex
\r
831 algorithms. It is possible that the high priority mutex task will
\r
832 execute as it shares a priority with this task. */
\r
833 if( xSemaphoreGive( xLocalMutex ) != pdPASS )
\r
835 xErrorDetected = pdTRUE;
\r
838 #if configUSE_PREEMPTION == 0
\r
842 /* The guarded variable is only incremented by the medium priority task,
\r
843 which still should not have executed as this task should remain at the
\r
844 higher priority, ensure this is the case. */
\r
845 if( ulGuardedVariable != 0 )
\r
847 xErrorDetected = pdTRUE;
\r
850 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
\r
852 xErrorDetected = pdTRUE;
\r
855 /* Now also give back the shared mutex, taking the held count back to 0.
\r
856 This time the priority of this task should be disinherited back to the
\r
857 priority at which it was created. This means the medium priority task
\r
858 should execute and increment the guarded variable. When this task next runs
\r
859 both the high and medium priority tasks will have been suspended again. */
\r
860 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
862 xErrorDetected = pdTRUE;
\r
865 #if configUSE_PREEMPTION == 0
\r
869 /* Check the guarded variable did indeed increment... */
\r
870 if( ulGuardedVariable != 1 )
\r
872 xErrorDetected = pdTRUE;
\r
875 /* ... and that the priority of this task has been disinherited to
\r
876 genqMUTEX_LOW_PRIORITY. */
\r
877 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
\r
879 xErrorDetected = pdTRUE;
\r
882 /*-----------------------------------------------------------*/
\r
884 static void prvLowPriorityMutexTask( void *pvParameters )
\r
886 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
\r
889 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
891 const char * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
\r
893 /* Queue a message for printing to say the task has started. */
\r
894 vPrintDisplayMessage( &pcTaskStartMsg );
\r
897 /* The local mutex is used to check the 'mutexs held' count. */
\r
898 xLocalMutex = xSemaphoreCreateMutex();
\r
899 configASSERT( xLocalMutex );
\r
903 /* The first tests exercise the priority inheritance when two mutexes
\r
904 are taken then returned in a different order to which they were
\r
906 prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );
\r
908 /* Just to show this task is still running. */
\r
911 #if configUSE_PREEMPTION == 0
\r
915 /* The second tests exercise the priority inheritance when two mutexes
\r
916 are taken then returned in the same order in which they were taken. */
\r
917 prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );
\r
919 /* Just to show this task is still running. */
\r
922 #if configUSE_PREEMPTION == 0
\r
926 #if( INCLUDE_xTaskAbortDelay == 1 )
\r
928 /* Tests the behaviour when a low priority task inherits the
\r
929 priority of a high priority task only for the high priority task to
\r
930 timeout before obtaining the mutex. */
\r
931 prvHighPriorityTimeout( xMutex );
\r
936 /*-----------------------------------------------------------*/
\r
938 static void prvMediumPriorityMutexTask( void *pvParameters )
\r
940 ( void ) pvParameters;
\r
944 /* The medium priority task starts by suspending itself. The low
\r
945 priority task will unsuspend this task when required. */
\r
946 vTaskSuspend( NULL );
\r
948 /* When this task unsuspends all it does is increment the guarded
\r
949 variable, this is so the low priority task knows that it has
\r
951 ulGuardedVariable++;
\r
954 /*-----------------------------------------------------------*/
\r
956 static void prvHighPriorityMutexTask( void *pvParameters )
\r
958 SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
\r
962 /* The high priority task starts by suspending itself. The low
\r
963 priority task will unsuspend this task when required. */
\r
964 vTaskSuspend( NULL );
\r
966 /* When this task unsuspends all it does is attempt to obtain the
\r
967 mutex. It should find the mutex is not available so a block time is
\r
969 if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
\r
971 /* This task would expect to obtain the mutex unless its wait for
\r
972 the mutex was aborted. */
\r
973 if( xBlockWasAborted == pdFALSE )
\r
975 xErrorDetected = pdTRUE;
\r
979 xBlockWasAborted = pdFALSE;
\r
984 /* When the mutex is eventually obtained it is just given back before
\r
985 returning to suspend ready for the next cycle. */
\r
986 if( xSemaphoreGive( xMutex ) != pdPASS )
\r
988 xErrorDetected = pdTRUE;
\r
993 /*-----------------------------------------------------------*/
\r
996 /* This is called to check that all the created tasks are still running. */
\r
997 BaseType_t xAreGenericQueueTasksStillRunning( void )
\r
999 static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
\r
1001 /* If the demo task is still running then we expect the loop counters to
\r
1002 have incremented since this function was last called. */
\r
1003 if( ulLastLoopCounter == ulLoopCounter )
\r
1005 xErrorDetected = pdTRUE;
\r
1008 if( ulLastLoopCounter2 == ulLoopCounter2 )
\r
1010 xErrorDetected = pdTRUE;
\r
1013 ulLastLoopCounter = ulLoopCounter;
\r
1014 ulLastLoopCounter2 = ulLoopCounter2;
\r
1016 /* Errors detected in the task itself will have latched xErrorDetected
\r
1019 return ( BaseType_t ) !xErrorDetected;
\r