2 FreeRTOS V7.5.1 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
6 ***************************************************************************
\r
8 * FreeRTOS provides completely free yet professionally developed, *
\r
9 * robust, strictly quality controlled, supported, and cross *
\r
10 * platform software that has become a de facto standard. *
\r
12 * Help yourself get started quickly and support the FreeRTOS *
\r
13 * project by purchasing a FreeRTOS tutorial book, reference *
\r
14 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
18 ***************************************************************************
\r
20 This file is part of the FreeRTOS distribution.
\r
22 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
23 the terms of the GNU General Public License (version 2) as published by the
\r
24 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
26 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
27 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
28 >>! the source code for proprietary components outside of the FreeRTOS
\r
31 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
32 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
33 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
34 link: http://www.freertos.org/a00114.html
\r
38 ***************************************************************************
\r
40 * Having a problem? Start by reading the FAQ "My application does *
\r
41 * not run, what could be wrong?" *
\r
43 * http://www.FreeRTOS.org/FAQHelp.html *
\r
45 ***************************************************************************
\r
47 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
48 license and Real Time Engineers Ltd. contact details.
\r
50 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
51 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
52 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
54 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
55 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
56 licenses offer ticketed support, indemnification and middleware.
\r
58 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
59 engineered and independently SIL3 certified version for use in safety and
\r
60 mission critical applications that require provable dependability.
\r
66 * This file contains some test scenarios that ensure tasks do not exit queue
\r
67 * send or receive functions prematurely. A description of the tests is
\r
68 * included within the code.
\r
71 /* Kernel includes. */
\r
72 #include "FreeRTOS.h"
\r
76 /* Demo includes. */
\r
77 #include "blocktim.h"
\r
79 /* Task priorities. Allow these to be overridden. */
\r
80 #ifndef bktPRIMARY_PRIORITY
\r
81 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
84 #ifndef bktSECONDARY_PRIORITY
\r
85 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
88 /* Task behaviour. */
\r
89 #define bktQUEUE_LENGTH ( 5 )
\r
90 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
91 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
92 #define bktALLOWABLE_MARGIN ( 15 )
\r
93 #define bktTIME_TO_BLOCK ( 175 )
\r
94 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
95 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
97 /* The queue on which the tasks block. */
\r
98 static xQueueHandle xTestQueue;
\r
100 /* Handle to the secondary task is required by the primary task for calls
\r
101 to vTaskSuspend/Resume(). */
\r
102 static xTaskHandle xSecondary;
\r
104 /* Used to ensure that tasks are still executing without error. */
\r
105 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
106 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
\r
108 /* Provides a simple mechanism for the primary task to know when the
\r
109 secondary task has executed. */
\r
110 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
112 /* The two test tasks. Their behaviour is commented within the files. */
\r
113 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
114 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
116 /*-----------------------------------------------------------*/
\r
118 void vCreateBlockTimeTasks( void )
\r
120 /* Create the queue on which the two tasks block. */
\r
121 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
123 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
124 in use. The queue registry is provided as a means for kernel aware
\r
125 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
126 is not being used. The call to vQueueAddToRegistry() will be removed
\r
127 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
128 defined to be less than 1. */
\r
129 vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );
\r
131 /* Create the two test tasks. */
\r
132 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
133 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
135 /*-----------------------------------------------------------*/
\r
137 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
139 portBASE_TYPE xItem, xData;
\r
140 portTickType xTimeWhenBlocking;
\r
141 portTickType xTimeToBlock, xBlockedTime;
\r
143 ( void ) pvParameters;
\r
147 /*********************************************************************
\r
150 Simple block time wakeup test on queue receives. */
\r
151 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
153 /* The queue is empty. Attempt to read from the queue using a block
\r
154 time. When we wake, ensure the delta in time is as expected. */
\r
155 xTimeToBlock = ( portTickType ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
157 xTimeWhenBlocking = xTaskGetTickCount();
\r
159 /* We should unblock after xTimeToBlock having not received
\r
160 anything on the queue. */
\r
161 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
163 xErrorOccurred = pdTRUE;
\r
166 /* How long were we blocked for? */
\r
167 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
169 if( xBlockedTime < xTimeToBlock )
\r
171 /* Should not have blocked for less than we requested. */
\r
172 xErrorOccurred = pdTRUE;
\r
175 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
177 /* Should not have blocked for longer than we requested,
\r
178 although we would not necessarily run as soon as we were
\r
179 unblocked so a margin is allowed. */
\r
180 xErrorOccurred = pdTRUE;
\r
184 /*********************************************************************
\r
187 Simple block time wakeup test on queue sends.
\r
189 First fill the queue. It should be empty so all sends should pass. */
\r
190 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
192 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
194 xErrorOccurred = pdTRUE;
\r
197 #if configUSE_PREEMPTION == 0
\r
202 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
204 /* The queue is full. Attempt to write to the queue using a block
\r
205 time. When we wake, ensure the delta in time is as expected. */
\r
206 xTimeToBlock = ( portTickType ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
208 xTimeWhenBlocking = xTaskGetTickCount();
\r
210 /* We should unblock after xTimeToBlock having not received
\r
211 anything on the queue. */
\r
212 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
214 xErrorOccurred = pdTRUE;
\r
217 /* How long were we blocked for? */
\r
218 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
220 if( xBlockedTime < xTimeToBlock )
\r
222 /* Should not have blocked for less than we requested. */
\r
223 xErrorOccurred = pdTRUE;
\r
226 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
228 /* Should not have blocked for longer than we requested,
\r
229 although we would not necessarily run as soon as we were
\r
230 unblocked so a margin is allowed. */
\r
231 xErrorOccurred = pdTRUE;
\r
235 /*********************************************************************
\r
238 Wake the other task, it will block attempting to post to the queue.
\r
239 When we read from the queue the other task will wake, but before it
\r
240 can run we will post to the queue again. When the other task runs it
\r
241 will find the queue still full, even though it was woken. It should
\r
242 recognise that its block time has not expired and return to block for
\r
243 the remains of its block time.
\r
245 Wake the other task so it blocks attempting to post to the already
\r
248 vTaskResume( xSecondary );
\r
250 /* We need to wait a little to ensure the other task executes. */
\r
251 while( xRunIndicator != bktRUN_INDICATOR )
\r
253 /* The other task has not yet executed. */
\r
254 vTaskDelay( bktSHORT_WAIT );
\r
256 /* Make sure the other task is blocked on the queue. */
\r
257 vTaskDelay( bktSHORT_WAIT );
\r
260 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
262 /* Now when we make space on the queue the other task should wake
\r
263 but not execute as this task has higher priority. */
\r
264 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
266 xErrorOccurred = pdTRUE;
\r
269 /* Now fill the queue again before the other task gets a chance to
\r
270 execute. If the other task had executed we would find the queue
\r
271 full ourselves, and the other task have set xRunIndicator. */
\r
272 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
274 xErrorOccurred = pdTRUE;
\r
277 if( xRunIndicator == bktRUN_INDICATOR )
\r
279 /* The other task should not have executed. */
\r
280 xErrorOccurred = pdTRUE;
\r
283 /* Raise the priority of the other task so it executes and blocks
\r
284 on the queue again. */
\r
285 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
287 /* The other task should now have re-blocked without exiting the
\r
289 if( xRunIndicator == bktRUN_INDICATOR )
\r
291 /* The other task should not have executed outside of the
\r
293 xErrorOccurred = pdTRUE;
\r
296 /* Set the priority back down. */
\r
297 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
300 /* Let the other task timeout. When it unblockes it will check that it
\r
301 unblocked at the correct time, then suspend itself. */
\r
302 while( xRunIndicator != bktRUN_INDICATOR )
\r
304 vTaskDelay( bktSHORT_WAIT );
\r
306 vTaskDelay( bktSHORT_WAIT );
\r
310 /*********************************************************************
\r
313 As per test 3 - but with the send and receive the other way around.
\r
314 The other task blocks attempting to read from the queue.
\r
316 Empty the queue. We should find that it is full. */
\r
317 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
319 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
321 xErrorOccurred = pdTRUE;
\r
325 /* Wake the other task so it blocks attempting to read from the
\r
326 already empty queue. */
\r
327 vTaskResume( xSecondary );
\r
329 /* We need to wait a little to ensure the other task executes. */
\r
330 while( xRunIndicator != bktRUN_INDICATOR )
\r
332 vTaskDelay( bktSHORT_WAIT );
\r
334 vTaskDelay( bktSHORT_WAIT );
\r
337 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
339 /* Now when we place an item on the queue the other task should
\r
340 wake but not execute as this task has higher priority. */
\r
341 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
343 xErrorOccurred = pdTRUE;
\r
346 /* Now empty the queue again before the other task gets a chance to
\r
347 execute. If the other task had executed we would find the queue
\r
348 empty ourselves, and the other task would be suspended. */
\r
349 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
351 xErrorOccurred = pdTRUE;
\r
354 if( xRunIndicator == bktRUN_INDICATOR )
\r
356 /* The other task should not have executed. */
\r
357 xErrorOccurred = pdTRUE;
\r
360 /* Raise the priority of the other task so it executes and blocks
\r
361 on the queue again. */
\r
362 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
364 /* The other task should now have re-blocked without exiting the
\r
366 if( xRunIndicator == bktRUN_INDICATOR )
\r
368 /* The other task should not have executed outside of the
\r
370 xErrorOccurred = pdTRUE;
\r
372 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
375 /* Let the other task timeout. When it unblockes it will check that it
\r
376 unblocked at the correct time, then suspend itself. */
\r
377 while( xRunIndicator != bktRUN_INDICATOR )
\r
379 vTaskDelay( bktSHORT_WAIT );
\r
381 vTaskDelay( bktSHORT_WAIT );
\r
386 /*-----------------------------------------------------------*/
\r
388 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
390 portTickType xTimeWhenBlocking, xBlockedTime;
\r
391 portBASE_TYPE xData;
\r
393 ( void ) pvParameters;
\r
397 /*********************************************************************
\r
400 This task does does not participate in these tests. */
\r
401 vTaskSuspend( NULL );
\r
403 /*********************************************************************
\r
406 The first thing we do is attempt to read from the queue. It should be
\r
407 full so we block. Note the time before we block so we can check the
\r
408 wake time is as per that expected. */
\r
409 xTimeWhenBlocking = xTaskGetTickCount();
\r
411 /* We should unblock after bktTIME_TO_BLOCK having not sent
\r
412 anything to the queue. */
\r
414 xRunIndicator = bktRUN_INDICATOR;
\r
415 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
417 xErrorOccurred = pdTRUE;
\r
420 /* How long were we inside the send function? */
\r
421 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
423 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
424 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
426 xErrorOccurred = pdTRUE;
\r
429 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
430 either. A margin is permitted as we would not necessarily run as
\r
431 soon as we unblocked. */
\r
432 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
434 xErrorOccurred = pdTRUE;
\r
437 /* Suspend ready for test 3. */
\r
438 xRunIndicator = bktRUN_INDICATOR;
\r
439 vTaskSuspend( NULL );
\r
441 /*********************************************************************
\r
444 As per test three, but with the send and receive reversed. */
\r
445 xTimeWhenBlocking = xTaskGetTickCount();
\r
447 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
448 anything on the queue. */
\r
449 xRunIndicator = bktRUN_INDICATOR;
\r
450 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
452 xErrorOccurred = pdTRUE;
\r
455 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
457 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
458 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
460 xErrorOccurred = pdTRUE;
\r
463 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
464 either. A margin is permitted as we would not necessarily run as soon
\r
465 as we unblocked. */
\r
466 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
468 xErrorOccurred = pdTRUE;
\r
471 xRunIndicator = bktRUN_INDICATOR;
\r
473 xSecondaryCycles++;
\r
476 /*-----------------------------------------------------------*/
\r
478 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
480 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
481 portBASE_TYPE xReturn = pdPASS;
\r
483 /* Have both tasks performed at least one cycle since this function was
\r
485 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
490 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
495 if( xErrorOccurred == pdTRUE )
\r
500 xLastSecondaryCycleCount = xSecondaryCycles;
\r
501 xLastPrimaryCycleCount = xPrimaryCycles;
\r