2 FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
28 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
29 >>! the source code for proprietary components outside of the FreeRTOS
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
67 * This file contains some test scenarios that ensure tasks do not exit queue
\r
68 * send or receive functions prematurely. A description of the tests is
\r
69 * included within the code.
\r
72 /* Kernel includes. */
\r
73 #include "FreeRTOS.h"
\r
77 /* Demo includes. */
\r
78 #include "blocktim.h"
\r
80 /* Task priorities. Allow these to be overridden. */
\r
81 #ifndef bktPRIMARY_PRIORITY
\r
82 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
85 #ifndef bktSECONDARY_PRIORITY
\r
86 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
89 /* Task behaviour. */
\r
90 #define bktQUEUE_LENGTH ( 5 )
\r
91 #define bktSHORT_WAIT ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )
\r
92 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
93 #define bktALLOWABLE_MARGIN ( 15 )
\r
94 #define bktTIME_TO_BLOCK ( 175 )
\r
95 #define bktDONT_BLOCK ( ( TickType_t ) 0 )
\r
96 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
98 /* The queue on which the tasks block. */
\r
99 static QueueHandle_t xTestQueue;
\r
101 /* Handle to the secondary task is required by the primary task for calls
\r
102 to vTaskSuspend/Resume(). */
\r
103 static TaskHandle_t xSecondary;
\r
105 /* Used to ensure that tasks are still executing without error. */
\r
106 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
107 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
\r
109 /* Provides a simple mechanism for the primary task to know when the
\r
110 secondary task has executed. */
\r
111 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
113 /* The two test tasks. Their behaviour is commented within the files. */
\r
114 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
115 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
117 /*-----------------------------------------------------------*/
\r
119 void vCreateBlockTimeTasks( void )
\r
121 /* Create the queue on which the two tasks block. */
\r
122 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
124 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
125 in use. The queue registry is provided as a means for kernel aware
\r
126 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
127 is not being used. The call to vQueueAddToRegistry() will be removed
\r
128 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
129 defined to be less than 1. */
\r
130 vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
\r
132 /* Create the two test tasks. */
\r
133 xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
134 xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
136 /*-----------------------------------------------------------*/
\r
138 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
140 portBASE_TYPE xItem, xData;
\r
141 TickType_t xTimeWhenBlocking;
\r
142 TickType_t xTimeToBlock, xBlockedTime;
\r
144 ( void ) pvParameters;
\r
148 /*********************************************************************
\r
151 Simple block time wakeup test on queue receives. */
\r
152 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
154 /* The queue is empty. Attempt to read from the queue using a block
\r
155 time. When we wake, ensure the delta in time is as expected. */
\r
156 xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
158 xTimeWhenBlocking = xTaskGetTickCount();
\r
160 /* We should unblock after xTimeToBlock having not received
\r
161 anything on the queue. */
\r
162 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
164 xErrorOccurred = pdTRUE;
\r
167 /* How long were we blocked for? */
\r
168 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
170 if( xBlockedTime < xTimeToBlock )
\r
172 /* Should not have blocked for less than we requested. */
\r
173 xErrorOccurred = pdTRUE;
\r
176 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
178 /* Should not have blocked for longer than we requested,
\r
179 although we would not necessarily run as soon as we were
\r
180 unblocked so a margin is allowed. */
\r
181 xErrorOccurred = pdTRUE;
\r
185 /*********************************************************************
\r
188 Simple block time wakeup test on queue sends.
\r
190 First fill the queue. It should be empty so all sends should pass. */
\r
191 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
193 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
195 xErrorOccurred = pdTRUE;
\r
198 #if configUSE_PREEMPTION == 0
\r
203 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
205 /* The queue is full. Attempt to write to the queue using a block
\r
206 time. When we wake, ensure the delta in time is as expected. */
\r
207 xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
209 xTimeWhenBlocking = xTaskGetTickCount();
\r
211 /* We should unblock after xTimeToBlock having not received
\r
212 anything on the queue. */
\r
213 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
215 xErrorOccurred = pdTRUE;
\r
218 /* How long were we blocked for? */
\r
219 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
221 if( xBlockedTime < xTimeToBlock )
\r
223 /* Should not have blocked for less than we requested. */
\r
224 xErrorOccurred = pdTRUE;
\r
227 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
229 /* Should not have blocked for longer than we requested,
\r
230 although we would not necessarily run as soon as we were
\r
231 unblocked so a margin is allowed. */
\r
232 xErrorOccurred = pdTRUE;
\r
236 /*********************************************************************
\r
239 Wake the other task, it will block attempting to post to the queue.
\r
240 When we read from the queue the other task will wake, but before it
\r
241 can run we will post to the queue again. When the other task runs it
\r
242 will find the queue still full, even though it was woken. It should
\r
243 recognise that its block time has not expired and return to block for
\r
244 the remains of its block time.
\r
246 Wake the other task so it blocks attempting to post to the already
\r
249 vTaskResume( xSecondary );
\r
251 /* We need to wait a little to ensure the other task executes. */
\r
252 while( xRunIndicator != bktRUN_INDICATOR )
\r
254 /* The other task has not yet executed. */
\r
255 vTaskDelay( bktSHORT_WAIT );
\r
257 /* Make sure the other task is blocked on the queue. */
\r
258 vTaskDelay( bktSHORT_WAIT );
\r
261 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
263 /* Now when we make space on the queue the other task should wake
\r
264 but not execute as this task has higher priority. */
\r
265 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
267 xErrorOccurred = pdTRUE;
\r
270 /* Now fill the queue again before the other task gets a chance to
\r
271 execute. If the other task had executed we would find the queue
\r
272 full ourselves, and the other task have set xRunIndicator. */
\r
273 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
275 xErrorOccurred = pdTRUE;
\r
278 if( xRunIndicator == bktRUN_INDICATOR )
\r
280 /* The other task should not have executed. */
\r
281 xErrorOccurred = pdTRUE;
\r
284 /* Raise the priority of the other task so it executes and blocks
\r
285 on the queue again. */
\r
286 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
288 /* The other task should now have re-blocked without exiting the
\r
290 if( xRunIndicator == bktRUN_INDICATOR )
\r
292 /* The other task should not have executed outside of the
\r
294 xErrorOccurred = pdTRUE;
\r
297 /* Set the priority back down. */
\r
298 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
301 /* Let the other task timeout. When it unblockes it will check that it
\r
302 unblocked at the correct time, then suspend itself. */
\r
303 while( xRunIndicator != bktRUN_INDICATOR )
\r
305 vTaskDelay( bktSHORT_WAIT );
\r
307 vTaskDelay( bktSHORT_WAIT );
\r
311 /*********************************************************************
\r
314 As per test 3 - but with the send and receive the other way around.
\r
315 The other task blocks attempting to read from the queue.
\r
317 Empty the queue. We should find that it is full. */
\r
318 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
320 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
322 xErrorOccurred = pdTRUE;
\r
326 /* Wake the other task so it blocks attempting to read from the
\r
327 already empty queue. */
\r
328 vTaskResume( xSecondary );
\r
330 /* We need to wait a little to ensure the other task executes. */
\r
331 while( xRunIndicator != bktRUN_INDICATOR )
\r
333 vTaskDelay( bktSHORT_WAIT );
\r
335 vTaskDelay( bktSHORT_WAIT );
\r
338 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
340 /* Now when we place an item on the queue the other task should
\r
341 wake but not execute as this task has higher priority. */
\r
342 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
344 xErrorOccurred = pdTRUE;
\r
347 /* Now empty the queue again before the other task gets a chance to
\r
348 execute. If the other task had executed we would find the queue
\r
349 empty ourselves, and the other task would be suspended. */
\r
350 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
352 xErrorOccurred = pdTRUE;
\r
355 if( xRunIndicator == bktRUN_INDICATOR )
\r
357 /* The other task should not have executed. */
\r
358 xErrorOccurred = pdTRUE;
\r
361 /* Raise the priority of the other task so it executes and blocks
\r
362 on the queue again. */
\r
363 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
365 /* The other task should now have re-blocked without exiting the
\r
367 if( xRunIndicator == bktRUN_INDICATOR )
\r
369 /* The other task should not have executed outside of the
\r
371 xErrorOccurred = pdTRUE;
\r
373 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
376 /* Let the other task timeout. When it unblockes it will check that it
\r
377 unblocked at the correct time, then suspend itself. */
\r
378 while( xRunIndicator != bktRUN_INDICATOR )
\r
380 vTaskDelay( bktSHORT_WAIT );
\r
382 vTaskDelay( bktSHORT_WAIT );
\r
387 /*-----------------------------------------------------------*/
\r
389 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
391 TickType_t xTimeWhenBlocking, xBlockedTime;
\r
392 portBASE_TYPE xData;
\r
394 ( void ) pvParameters;
\r
398 /*********************************************************************
\r
401 This task does does not participate in these tests. */
\r
402 vTaskSuspend( NULL );
\r
404 /*********************************************************************
\r
407 The first thing we do is attempt to read from the queue. It should be
\r
408 full so we block. Note the time before we block so we can check the
\r
409 wake time is as per that expected. */
\r
410 xTimeWhenBlocking = xTaskGetTickCount();
\r
412 /* We should unblock after bktTIME_TO_BLOCK having not sent
\r
413 anything to the queue. */
\r
415 xRunIndicator = bktRUN_INDICATOR;
\r
416 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
418 xErrorOccurred = pdTRUE;
\r
421 /* How long were we inside the send function? */
\r
422 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
424 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
425 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
427 xErrorOccurred = pdTRUE;
\r
430 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
431 either. A margin is permitted as we would not necessarily run as
\r
432 soon as we unblocked. */
\r
433 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
435 xErrorOccurred = pdTRUE;
\r
438 /* Suspend ready for test 3. */
\r
439 xRunIndicator = bktRUN_INDICATOR;
\r
440 vTaskSuspend( NULL );
\r
442 /*********************************************************************
\r
445 As per test three, but with the send and receive reversed. */
\r
446 xTimeWhenBlocking = xTaskGetTickCount();
\r
448 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
449 anything on the queue. */
\r
450 xRunIndicator = bktRUN_INDICATOR;
\r
451 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
453 xErrorOccurred = pdTRUE;
\r
456 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
458 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
459 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
461 xErrorOccurred = pdTRUE;
\r
464 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
465 either. A margin is permitted as we would not necessarily run as soon
\r
466 as we unblocked. */
\r
467 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
469 xErrorOccurred = pdTRUE;
\r
472 xRunIndicator = bktRUN_INDICATOR;
\r
474 xSecondaryCycles++;
\r
477 /*-----------------------------------------------------------*/
\r
479 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
481 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
482 portBASE_TYPE xReturn = pdPASS;
\r
484 /* Have both tasks performed at least one cycle since this function was
\r
486 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
491 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
496 if( xErrorOccurred == pdTRUE )
\r
501 xLastSecondaryCycleCount = xSecondaryCycles;
\r
502 xLastPrimaryCycleCount = xPrimaryCycles;
\r