2 FreeRTOS V5.4.1 - Copyright (C) 2009 Real Time Engineers Ltd.
\r
4 This file is part of the FreeRTOS distribution.
\r
6 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
7 the terms of the GNU General Public License (version 2) as published by the
\r
8 Free Software Foundation and modified by the FreeRTOS exception.
\r
9 **NOTE** The exception to the GPL is included to allow you to distribute a
\r
10 combined work that includes FreeRTOS without being obliged to provide the
\r
11 source code for proprietary components outside of the FreeRTOS kernel.
\r
12 Alternative commercial license and support terms are also available upon
\r
13 request. See the licensing section of http://www.FreeRTOS.org for full
\r
16 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
\r
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
\r
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
21 You should have received a copy of the GNU General Public License along
\r
22 with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
\r
23 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
\r
26 ***************************************************************************
\r
28 * Looking for a quick start? Then check out the FreeRTOS eBook! *
\r
29 * See http://www.FreeRTOS.org/Documentation for details *
\r
31 ***************************************************************************
\r
35 Please ensure to read the configuration and relevant port sections of the
\r
36 online documentation.
\r
38 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
41 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
44 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
45 licensing and training services.
\r
49 * This is a version of BlockTim.c that uses the light weight API.
\r
51 * This file contains some test scenarios that ensure tasks do not exit queue
\r
52 * send or receive functions prematurely. A description of the tests is
\r
53 * included within the code.
\r
56 /* Kernel includes. */
\r
57 #include "FreeRTOS.h"
\r
61 /* Demo includes. */
\r
62 #include "AltBlock.h"
\r
64 /* Task priorities. */
\r
65 #define bktPRIMARY_PRIORITY ( 3 )
\r
66 #define bktSECONDARY_PRIORITY ( 2 )
\r
68 /* Task behaviour. */
\r
69 #define bktQUEUE_LENGTH ( 5 )
\r
70 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
71 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
72 #define bktALLOWABLE_MARGIN ( 12 )
\r
73 #define bktTIME_TO_BLOCK ( 175 )
\r
74 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
75 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
77 /* The queue on which the tasks block. */
\r
78 static xQueueHandle xTestQueue;
\r
80 /* Handle to the secondary task is required by the primary task for calls
\r
81 to vTaskSuspend/Resume(). */
\r
82 static xTaskHandle xSecondary;
\r
84 /* Used to ensure that tasks are still executing without error. */
\r
85 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
86 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
88 /* Provides a simple mechanism for the primary task to know when the
\r
89 secondary task has executed. */
\r
90 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
92 /* The two test tasks. Their behaviour is commented within the files. */
\r
93 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
94 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
96 /*-----------------------------------------------------------*/
\r
98 void vCreateAltBlockTimeTasks( void )
\r
100 /* Create the queue on which the two tasks block. */
\r
101 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
103 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
104 in use. The queue registry is provided as a means for kernel aware
\r
105 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
106 is not being used. The call to vQueueAddToRegistry() will be removed
\r
107 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
108 defined to be less than 1. */
\r
109 vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
\r
112 /* Create the two test tasks. */
\r
113 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
114 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
116 /*-----------------------------------------------------------*/
\r
118 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
120 portBASE_TYPE xItem, xData;
\r
121 portTickType xTimeWhenBlocking;
\r
122 portTickType xTimeToBlock, xBlockedTime;
\r
125 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
127 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
129 /* Queue a message for printing to say the task has started. */
\r
130 vPrintDisplayMessage( &pcTaskStartMsg );
\r
133 ( void ) pvParameters;
\r
137 /*********************************************************************
\r
140 Simple block time wakeup test on queue receives. */
\r
141 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
143 /* The queue is empty. Attempt to read from the queue using a block
\r
144 time. When we wake, ensure the delta in time is as expected. */
\r
145 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
147 /* A critical section is used to minimise the jitter in the time
\r
149 portENTER_CRITICAL();
\r
151 xTimeWhenBlocking = xTaskGetTickCount();
\r
153 /* We should unblock after xTimeToBlock having not received
\r
154 anything on the queue. */
\r
155 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
157 xErrorOccurred = pdTRUE;
\r
160 /* How long were we blocked for? */
\r
161 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
163 portEXIT_CRITICAL();
\r
165 if( xBlockedTime < xTimeToBlock )
\r
167 /* Should not have blocked for less than we requested. */
\r
168 xErrorOccurred = pdTRUE;
\r
171 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
173 /* Should not have blocked for longer than we requested,
\r
174 although we would not necessarily run as soon as we were
\r
175 unblocked so a margin is allowed. */
\r
176 xErrorOccurred = pdTRUE;
\r
181 #if configUSE_PREEMPTION == 0
\r
186 /*********************************************************************
\r
189 Simple block time wakeup test on queue sends.
\r
191 First fill the queue. It should be empty so all sends should pass. */
\r
192 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
194 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
196 xErrorOccurred = pdTRUE;
\r
200 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
202 /* The queue is full. Attempt to write to the queue using a block
\r
203 time. When we wake, ensure the delta in time is as expected. */
\r
204 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
206 portENTER_CRITICAL();
\r
208 xTimeWhenBlocking = xTaskGetTickCount();
\r
210 /* We should unblock after xTimeToBlock having not received
\r
211 anything on the queue. */
\r
212 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
214 xErrorOccurred = pdTRUE;
\r
217 /* How long were we blocked for? */
\r
218 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
220 portEXIT_CRITICAL();
\r
222 if( xBlockedTime < xTimeToBlock )
\r
224 /* Should not have blocked for less than we requested. */
\r
225 xErrorOccurred = pdTRUE;
\r
228 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
230 /* Should not have blocked for longer than we requested,
\r
231 although we would not necessarily run as soon as we were
\r
232 unblocked so a margin is allowed. */
\r
233 xErrorOccurred = pdTRUE;
\r
237 #if configUSE_PREEMPTION == 0
\r
242 /*********************************************************************
\r
245 Wake the other task, it will block attempting to post to the queue.
\r
246 When we read from the queue the other task will wake, but before it
\r
247 can run we will post to the queue again. When the other task runs it
\r
248 will find the queue still full, even though it was woken. It should
\r
249 recognise that its block time has not expired and return to block for
\r
250 the remains of its block time.
\r
252 Wake the other task so it blocks attempting to post to the already
\r
255 vTaskResume( xSecondary );
\r
257 /* We need to wait a little to ensure the other task executes. */
\r
258 while( xRunIndicator != bktRUN_INDICATOR )
\r
260 /* The other task has not yet executed. */
\r
261 vTaskDelay( bktSHORT_WAIT );
\r
263 /* Make sure the other task is blocked on the queue. */
\r
264 vTaskDelay( bktSHORT_WAIT );
\r
267 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
269 /* Now when we make space on the queue the other task should wake
\r
270 but not execute as this task has higher priority. */
\r
271 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
273 xErrorOccurred = pdTRUE;
\r
276 /* Now fill the queue again before the other task gets a chance to
\r
277 execute. If the other task had executed we would find the queue
\r
278 full ourselves, and the other task have set xRunIndicator. */
\r
279 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
281 xErrorOccurred = pdTRUE;
\r
284 if( xRunIndicator == bktRUN_INDICATOR )
\r
286 /* The other task should not have executed. */
\r
287 xErrorOccurred = pdTRUE;
\r
290 /* Raise the priority of the other task so it executes and blocks
\r
291 on the queue again. */
\r
292 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
294 /* The other task should now have re-blocked without exiting the
\r
296 if( xRunIndicator == bktRUN_INDICATOR )
\r
298 /* The other task should not have executed outside of the
\r
300 xErrorOccurred = pdTRUE;
\r
303 /* Set the priority back down. */
\r
304 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
307 /* Let the other task timeout. When it unblockes it will check that it
\r
308 unblocked at the correct time, then suspend itself. */
\r
309 while( xRunIndicator != bktRUN_INDICATOR )
\r
311 vTaskDelay( bktSHORT_WAIT );
\r
313 vTaskDelay( bktSHORT_WAIT );
\r
316 #if configUSE_PREEMPTION == 0
\r
320 /*********************************************************************
\r
323 As per test 3 - but with the send and receive the other way around.
\r
324 The other task blocks attempting to read from the queue.
\r
326 Empty the queue. We should find that it is full. */
\r
327 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
329 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
331 xErrorOccurred = pdTRUE;
\r
335 /* Wake the other task so it blocks attempting to read from the
\r
336 already empty queue. */
\r
337 vTaskResume( xSecondary );
\r
339 /* We need to wait a little to ensure the other task executes. */
\r
340 while( xRunIndicator != bktRUN_INDICATOR )
\r
342 vTaskDelay( bktSHORT_WAIT );
\r
344 vTaskDelay( bktSHORT_WAIT );
\r
347 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
349 /* Now when we place an item on the queue the other task should
\r
350 wake but not execute as this task has higher priority. */
\r
351 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
353 xErrorOccurred = pdTRUE;
\r
356 /* Now empty the queue again before the other task gets a chance to
\r
357 execute. If the other task had executed we would find the queue
\r
358 empty ourselves, and the other task would be suspended. */
\r
359 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
361 xErrorOccurred = pdTRUE;
\r
364 if( xRunIndicator == bktRUN_INDICATOR )
\r
366 /* The other task should not have executed. */
\r
367 xErrorOccurred = pdTRUE;
\r
370 /* Raise the priority of the other task so it executes and blocks
\r
371 on the queue again. */
\r
372 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
374 /* The other task should now have re-blocked without exiting the
\r
376 if( xRunIndicator == bktRUN_INDICATOR )
\r
378 /* The other task should not have executed outside of the
\r
380 xErrorOccurred = pdTRUE;
\r
382 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
385 /* Let the other task timeout. When it unblockes it will check that it
\r
386 unblocked at the correct time, then suspend itself. */
\r
387 while( xRunIndicator != bktRUN_INDICATOR )
\r
389 vTaskDelay( bktSHORT_WAIT );
\r
391 vTaskDelay( bktSHORT_WAIT );
\r
396 /*-----------------------------------------------------------*/
\r
398 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
400 portTickType xTimeWhenBlocking, xBlockedTime;
\r
401 portBASE_TYPE xData;
\r
404 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
406 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
408 /* Queue a message for printing to say the task has started. */
\r
409 vPrintDisplayMessage( &pcTaskStartMsg );
\r
412 ( void ) pvParameters;
\r
416 /*********************************************************************
\r
419 This task does does not participate in these tests. */
\r
420 vTaskSuspend( NULL );
\r
422 /*********************************************************************
\r
425 The first thing we do is attempt to read from the queue. It should be
\r
426 full so we block. Note the time before we block so we can check the
\r
427 wake time is as per that expected. */
\r
428 portENTER_CRITICAL();
\r
430 xTimeWhenBlocking = xTaskGetTickCount();
\r
432 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
433 anything on the queue. */
\r
435 xRunIndicator = bktRUN_INDICATOR;
\r
436 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
438 xErrorOccurred = pdTRUE;
\r
441 /* How long were we inside the send function? */
\r
442 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
444 portEXIT_CRITICAL();
\r
446 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
447 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
449 xErrorOccurred = pdTRUE;
\r
452 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
453 either. A margin is permitted as we would not necessarily run as
\r
454 soon as we unblocked. */
\r
455 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
457 xErrorOccurred = pdTRUE;
\r
460 /* Suspend ready for test 3. */
\r
461 xRunIndicator = bktRUN_INDICATOR;
\r
462 vTaskSuspend( NULL );
\r
464 /*********************************************************************
\r
467 As per test three, but with the send and receive reversed. */
\r
468 portENTER_CRITICAL();
\r
470 xTimeWhenBlocking = xTaskGetTickCount();
\r
472 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
473 anything on the queue. */
\r
474 xRunIndicator = bktRUN_INDICATOR;
\r
475 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
477 xErrorOccurred = pdTRUE;
\r
480 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
482 portEXIT_CRITICAL();
\r
484 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
485 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
487 xErrorOccurred = pdTRUE;
\r
490 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
491 either. A margin is permitted as we would not necessarily run as soon
\r
492 as we unblocked. */
\r
493 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
495 xErrorOccurred = pdTRUE;
\r
498 xRunIndicator = bktRUN_INDICATOR;
\r
500 xSecondaryCycles++;
\r
503 /*-----------------------------------------------------------*/
\r
505 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
\r
507 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
508 portBASE_TYPE xReturn = pdPASS;
\r
510 /* Have both tasks performed at least one cycle since this function was
\r
512 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
517 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
522 if( xErrorOccurred == pdTRUE )
\r
527 xLastSecondaryCycleCount = xSecondaryCycles;
\r
528 xLastPrimaryCycleCount = xPrimaryCycles;
\r