2 FreeRTOS.org V4.2.1 - Copyright (C) 2003-2007 Richard Barry.
\r
4 This file is part of the FreeRTOS.org distribution.
\r
6 FreeRTOS.org is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 FreeRTOS.org is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with FreeRTOS.org; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
20 A special exception to the GPL can be applied should you wish to distribute
\r
21 a combined work that includes FreeRTOS.org, without being obliged to provide
\r
22 the source code for any proprietary components. See the licensing section
\r
23 of http://www.FreeRTOS.org for full details of how and when the exception
\r
26 ***************************************************************************
\r
27 See http://www.FreeRTOS.org for documentation, latest information, license
\r
28 and contact details. Please ensure to read the configuration and relevant
\r
29 port sections of the online documentation.
\r
31 Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
\r
32 with commercial development and support options.
\r
33 ***************************************************************************
\r
37 * This file contains some test scenarios that ensure tasks do not exit queue
\r
38 * send or receive functions prematurely. A description of the tests is
\r
39 * included within the code.
\r
42 /* Kernel includes. */
\r
43 #include "FreeRTOS.h"
\r
47 /* Task priorities. */
\r
48 #define bktPRIMARY_PRIORITY ( 3 )
\r
49 #define bktSECONDARY_PRIORITY ( 2 )
\r
51 /* Task behaviour. */
\r
52 #define bktQUEUE_LENGTH ( 5 )
\r
53 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
54 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
55 #define bktALLOWABLE_MARGIN ( 12 )
\r
56 #define bktTIME_TO_BLOCK ( 175 )
\r
57 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
58 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
60 /* The queue on which the tasks block. */
\r
61 static xQueueHandle xTestQueue;
\r
63 /* Handle to the secondary task is required by the primary task for calls
\r
64 to vTaskSuspend/Resume(). */
\r
65 static xTaskHandle xSecondary;
\r
67 /* Used to ensure that tasks are still executing without error. */
\r
68 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
69 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
71 /* Provides a simple mechanism for the primary task to know when the
\r
72 secondary task has executed. */
\r
73 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
75 /* The two test tasks. Their behaviour is commented within the files. */
\r
76 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
77 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
79 /*-----------------------------------------------------------*/
\r
81 void vCreateBlockTimeTasks( void )
\r
83 /* Create the queue on which the two tasks block. */
\r
84 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
86 /* Create the two test tasks. */
\r
87 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
88 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
90 /*-----------------------------------------------------------*/
\r
92 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
94 portBASE_TYPE xItem, xData;
\r
95 portTickType xTimeWhenBlocking;
\r
96 portTickType xTimeToBlock, xBlockedTime;
\r
100 /*********************************************************************
\r
103 Simple block time wakeup test on queue receives. */
\r
104 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
106 /* The queue is empty. Attempt to read from the queue using a block
\r
107 time. When we wake, ensure the delta in time is as expected. */
\r
108 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
110 /* A critical section is used to minimise the jitter in the time
\r
112 portENTER_CRITICAL();
\r
114 xTimeWhenBlocking = xTaskGetTickCount();
\r
116 /* We should unblock after xTimeToBlock having not received
\r
117 anything on the queue. */
\r
118 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
120 xErrorOccurred = pdTRUE;
\r
123 /* How long were we blocked for? */
\r
124 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
126 portEXIT_CRITICAL();
\r
128 if( xBlockedTime < xTimeToBlock )
\r
130 /* Should not have blocked for less than we requested. */
\r
131 xErrorOccurred = pdTRUE;
\r
134 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
136 /* Should not have blocked for longer than we requested,
\r
137 although we would not necessarily run as soon as we were
\r
138 unblocked so a margin is allowed. */
\r
139 xErrorOccurred = pdTRUE;
\r
143 /*********************************************************************
\r
146 Simple block time wakeup test on queue sends.
\r
148 First fill the queue. It should be empty so all sends should pass. */
\r
149 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
151 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
153 xErrorOccurred = pdTRUE;
\r
157 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
159 /* The queue is full. Attempt to write to the queue using a block
\r
160 time. When we wake, ensure the delta in time is as expected. */
\r
161 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
163 portENTER_CRITICAL();
\r
165 xTimeWhenBlocking = xTaskGetTickCount();
\r
167 /* We should unblock after xTimeToBlock having not received
\r
168 anything on the queue. */
\r
169 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
171 xErrorOccurred = pdTRUE;
\r
174 /* How long were we blocked for? */
\r
175 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
177 portEXIT_CRITICAL();
\r
179 if( xBlockedTime < xTimeToBlock )
\r
181 /* Should not have blocked for less than we requested. */
\r
182 xErrorOccurred = pdTRUE;
\r
185 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
187 /* Should not have blocked for longer than we requested,
\r
188 although we would not necessarily run as soon as we were
\r
189 unblocked so a margin is allowed. */
\r
190 xErrorOccurred = pdTRUE;
\r
195 /*********************************************************************
\r
198 Wake the other task, it will block attempting to post to the queue.
\r
199 When we read from the queue the other task will wake, but before it
\r
200 can run we will post to the queue again. When the other task runs it
\r
201 will find the queue still full, even though it was woken. It should
\r
202 recognise that its block time has not expired and return to block for
\r
203 the remains of its block time.
\r
205 Wake the other task so it blocks attempting to post to the already
\r
208 vTaskResume( xSecondary );
\r
210 /* We need to wait a little to ensure the other task executes. */
\r
211 while( xRunIndicator != bktRUN_INDICATOR )
\r
213 /* The other task has not yet executed. */
\r
214 vTaskDelay( bktSHORT_WAIT );
\r
216 /* Make sure the other task is blocked on the queue. */
\r
217 vTaskDelay( bktSHORT_WAIT );
\r
220 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
222 /* Now when we make space on the queue the other task should wake
\r
223 but not execute as this task has higher priority. */
\r
224 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
226 xErrorOccurred = pdTRUE;
\r
229 /* Now fill the queue again before the other task gets a chance to
\r
230 execute. If the other task had executed we would find the queue
\r
231 full ourselves, and the other task have set xRunIndicator. */
\r
232 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
234 xErrorOccurred = pdTRUE;
\r
237 if( xRunIndicator == bktRUN_INDICATOR )
\r
239 /* The other task should not have executed. */
\r
240 xErrorOccurred = pdTRUE;
\r
243 /* Raise the priority of the other task so it executes and blocks
\r
244 on the queue again. */
\r
245 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
247 /* The other task should now have re-blocked without exiting the
\r
249 if( xRunIndicator == bktRUN_INDICATOR )
\r
251 /* The other task should not have executed outside of the
\r
253 xErrorOccurred = pdTRUE;
\r
256 /* Set the priority back down. */
\r
257 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
260 /* Let the other task timeout. When it unblockes it will check that it
\r
261 unblocked at the correct time, then suspend itself. */
\r
262 while( xRunIndicator != bktRUN_INDICATOR )
\r
264 vTaskDelay( bktSHORT_WAIT );
\r
266 vTaskDelay( bktSHORT_WAIT );
\r
270 /*********************************************************************
\r
273 As per test 3 - but with the send and receive the other way around.
\r
274 The other task blocks attempting to read from the queue.
\r
276 Empty the queue. We should find that it is full. */
\r
277 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
279 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
281 xErrorOccurred = pdTRUE;
\r
285 /* Wake the other task so it blocks attempting to read from the
\r
286 already empty queue. */
\r
287 vTaskResume( xSecondary );
\r
289 /* We need to wait a little to ensure the other task executes. */
\r
290 while( xRunIndicator != bktRUN_INDICATOR )
\r
292 vTaskDelay( bktSHORT_WAIT );
\r
294 vTaskDelay( bktSHORT_WAIT );
\r
297 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
299 /* Now when we place an item on the queue the other task should
\r
300 wake but not execute as this task has higher priority. */
\r
301 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
303 xErrorOccurred = pdTRUE;
\r
306 /* Now empty the queue again before the other task gets a chance to
\r
307 execute. If the other task had executed we would find the queue
\r
308 empty ourselves, and the other task would be suspended. */
\r
309 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
311 xErrorOccurred = pdTRUE;
\r
314 if( xRunIndicator == bktRUN_INDICATOR )
\r
316 /* The other task should not have executed. */
\r
317 xErrorOccurred = pdTRUE;
\r
320 /* Raise the priority of the other task so it executes and blocks
\r
321 on the queue again. */
\r
322 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
324 /* The other task should now have re-blocked without exiting the
\r
326 if( xRunIndicator == bktRUN_INDICATOR )
\r
328 /* The other task should not have executed outside of the
\r
330 xErrorOccurred = pdTRUE;
\r
332 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
335 /* Let the other task timeout. When it unblockes it will check that it
\r
336 unblocked at the correct time, then suspend itself. */
\r
337 while( xRunIndicator != bktRUN_INDICATOR )
\r
339 vTaskDelay( bktSHORT_WAIT );
\r
341 vTaskDelay( bktSHORT_WAIT );
\r
346 /*-----------------------------------------------------------*/
\r
348 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
350 portTickType xTimeWhenBlocking, xBlockedTime;
\r
351 portBASE_TYPE xData;
\r
355 /*********************************************************************
\r
358 This task does does not participate in these tests. */
\r
359 vTaskSuspend( NULL );
\r
361 /*********************************************************************
\r
364 The first thing we do is attempt to read from the queue. It should be
\r
365 full so we block. Note the time before we block so we can check the
\r
366 wake time is as per that expected. */
\r
367 portENTER_CRITICAL();
\r
369 xTimeWhenBlocking = xTaskGetTickCount();
\r
371 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
372 anything on the queue. */
\r
374 xRunIndicator = bktRUN_INDICATOR;
\r
375 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
377 xErrorOccurred = pdTRUE;
\r
380 /* How long were we inside the send function? */
\r
381 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
383 portEXIT_CRITICAL();
\r
385 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
386 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
388 xErrorOccurred = pdTRUE;
\r
391 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
392 either. A margin is permitted as we would not necessarily run as
\r
393 soon as we unblocked. */
\r
394 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
396 xErrorOccurred = pdTRUE;
\r
399 /* Suspend ready for test 3. */
\r
400 xRunIndicator = bktRUN_INDICATOR;
\r
401 vTaskSuspend( NULL );
\r
403 /*********************************************************************
\r
406 As per test three, but with the send and receive reversed. */
\r
407 portENTER_CRITICAL();
\r
409 xTimeWhenBlocking = xTaskGetTickCount();
\r
411 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
412 anything on the queue. */
\r
413 xRunIndicator = bktRUN_INDICATOR;
\r
414 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
416 xErrorOccurred = pdTRUE;
\r
419 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
421 portEXIT_CRITICAL();
\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 soon
\r
431 as we unblocked. */
\r
432 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
434 xErrorOccurred = pdTRUE;
\r
437 xRunIndicator = bktRUN_INDICATOR;
\r
439 xSecondaryCycles++;
\r
442 /*-----------------------------------------------------------*/
\r
444 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
446 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
447 portBASE_TYPE xReturn = pdPASS;
\r
449 /* Have both tasks performed at least one cycle since this function was
\r
451 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
456 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
461 if( xErrorOccurred == pdTRUE )
\r
466 xLastSecondaryCycleCount = xSecondaryCycles;
\r
467 xLastPrimaryCycleCount = xPrimaryCycles;
\r