2 FreeRTOS.org V4.1.1 - Copyright (C) 2003-2006 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
30 ***************************************************************************
\r
34 * This file contains some test scenarios that ensure tasks do not exit queue
\r
35 * send or receive functions prematurely. A description of the tests is
\r
36 * included within the code.
\r
39 /* Kernel includes. */
\r
40 #include "FreeRTOS.h"
\r
44 /* Task priorities. */
\r
45 #define bktPRIMARY_PRIORITY ( 3 )
\r
46 #define bktSECONDARY_PRIORITY ( 2 )
\r
48 /* Task behaviour. */
\r
49 #define bktQUEUE_LENGTH ( 5 )
\r
50 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
51 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
52 #define bktALLOWABLE_MARGIN ( 12 )
\r
53 #define bktTIME_TO_BLOCK ( 175 )
\r
54 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
55 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
57 /* The queue on which the tasks block. */
\r
58 static xQueueHandle xTestQueue;
\r
60 /* Handle to the secondary task is required by the primary task for calls
\r
61 to vTaskSuspend/Resume(). */
\r
62 static xTaskHandle xSecondary;
\r
64 /* Used to ensure that tasks are still executing without error. */
\r
65 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
66 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
68 /* Provides a simple mechanism for the primary task to know when the
\r
69 secondary task has executed. */
\r
70 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
72 /* The two test tasks. Their behaviour is commented within the files. */
\r
73 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
74 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
76 /*-----------------------------------------------------------*/
\r
78 void vCreateBlockTimeTasks( void )
\r
80 /* Create the queue on which the two tasks block. */
\r
81 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
83 /* Create the two test tasks. */
\r
84 xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
85 xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
87 /*-----------------------------------------------------------*/
\r
89 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
91 portBASE_TYPE xItem, xData;
\r
92 portTickType xTimeWhenBlocking;
\r
93 portTickType xTimeToBlock, xBlockedTime;
\r
97 /*********************************************************************
\r
100 Simple block time wakeup test on queue receives. */
\r
101 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
103 /* The queue is empty. Attempt to read from the queue using a block
\r
104 time. When we wake, ensure the delta in time is as expected. */
\r
105 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
107 /* A critical section is used to minimise the jitter in the time
\r
109 portENTER_CRITICAL();
\r
111 xTimeWhenBlocking = xTaskGetTickCount();
\r
113 /* We should unblock after xTimeToBlock having not received
\r
114 anything on the queue. */
\r
115 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
117 xErrorOccurred = pdTRUE;
\r
120 /* How long were we blocked for? */
\r
121 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
123 portEXIT_CRITICAL();
\r
125 if( xBlockedTime < xTimeToBlock )
\r
127 /* Should not have blocked for less than we requested. */
\r
128 xErrorOccurred = pdTRUE;
\r
131 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
133 /* Should not have blocked for longer than we requested,
\r
134 although we would not necessarily run as soon as we were
\r
135 unblocked so a margin is allowed. */
\r
136 xErrorOccurred = pdTRUE;
\r
140 /*********************************************************************
\r
143 Simple block time wakeup test on queue sends.
\r
145 First fill the queue. It should be empty so all sends should pass. */
\r
146 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
148 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
150 xErrorOccurred = pdTRUE;
\r
154 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
156 /* The queue is full. Attempt to write to the queue using a block
\r
157 time. When we wake, ensure the delta in time is as expected. */
\r
158 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
160 portENTER_CRITICAL();
\r
162 xTimeWhenBlocking = xTaskGetTickCount();
\r
164 /* We should unblock after xTimeToBlock having not received
\r
165 anything on the queue. */
\r
166 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
168 xErrorOccurred = pdTRUE;
\r
171 /* How long were we blocked for? */
\r
172 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
174 portEXIT_CRITICAL();
\r
176 if( xBlockedTime < xTimeToBlock )
\r
178 /* Should not have blocked for less than we requested. */
\r
179 xErrorOccurred = pdTRUE;
\r
182 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
184 /* Should not have blocked for longer than we requested,
\r
185 although we would not necessarily run as soon as we were
\r
186 unblocked so a margin is allowed. */
\r
187 xErrorOccurred = pdTRUE;
\r
192 /*********************************************************************
\r
195 Wake the other task, it will block attempting to post to the queue.
\r
196 When we read from the queue the other task will wake, but before it
\r
197 can run we will post to the queue again. When the other task runs it
\r
198 will find the queue still full, even though it was woken. It should
\r
199 recognise that its block time has not expired and return to block for
\r
200 the remains of its block time.
\r
202 Wake the other task so it blocks attempting to post to the already
\r
205 vTaskResume( xSecondary );
\r
207 /* We need to wait a little to ensure the other task executes. */
\r
208 while( xRunIndicator != bktRUN_INDICATOR )
\r
210 /* The other task has not yet executed. */
\r
211 vTaskDelay( bktSHORT_WAIT );
\r
213 /* Make sure the other task is blocked on the queue. */
\r
214 vTaskDelay( bktSHORT_WAIT );
\r
217 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
219 /* Now when we make space on the queue the other task should wake
\r
220 but not execute as this task has higher priority. */
\r
221 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
223 xErrorOccurred = pdTRUE;
\r
226 /* Now fill the queue again before the other task gets a chance to
\r
227 execute. If the other task had executed we would find the queue
\r
228 full ourselves, and the other task have set xRunIndicator. */
\r
229 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
231 xErrorOccurred = pdTRUE;
\r
234 if( xRunIndicator == bktRUN_INDICATOR )
\r
236 /* The other task should not have executed. */
\r
237 xErrorOccurred = pdTRUE;
\r
240 /* Raise the priority of the other task so it executes and blocks
\r
241 on the queue again. */
\r
242 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
244 /* The other task should now have re-blocked without exiting the
\r
246 if( xRunIndicator == bktRUN_INDICATOR )
\r
248 /* The other task should not have executed outside of the
\r
250 xErrorOccurred = pdTRUE;
\r
253 /* Set the priority back down. */
\r
254 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
257 /* Let the other task timeout. When it unblockes it will check that it
\r
258 unblocked at the correct time, then suspend itself. */
\r
259 while( xRunIndicator != bktRUN_INDICATOR )
\r
261 vTaskDelay( bktSHORT_WAIT );
\r
263 vTaskDelay( bktSHORT_WAIT );
\r
267 /*********************************************************************
\r
270 As per test 3 - but with the send and receive the other way around.
\r
271 The other task blocks attempting to read from the queue.
\r
273 Empty the queue. We should find that it is full. */
\r
274 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
276 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
278 xErrorOccurred = pdTRUE;
\r
282 /* Wake the other task so it blocks attempting to read from the
\r
283 already empty queue. */
\r
284 vTaskResume( xSecondary );
\r
286 /* We need to wait a little to ensure the other task executes. */
\r
287 while( xRunIndicator != bktRUN_INDICATOR )
\r
289 vTaskDelay( bktSHORT_WAIT );
\r
291 vTaskDelay( bktSHORT_WAIT );
\r
294 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
296 /* Now when we place an item on the queue the other task should
\r
297 wake but not execute as this task has higher priority. */
\r
298 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
300 xErrorOccurred = pdTRUE;
\r
303 /* Now empty the queue again before the other task gets a chance to
\r
304 execute. If the other task had executed we would find the queue
\r
305 empty ourselves, and the other task would be suspended. */
\r
306 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
308 xErrorOccurred = pdTRUE;
\r
311 if( xRunIndicator == bktRUN_INDICATOR )
\r
313 /* The other task should not have executed. */
\r
314 xErrorOccurred = pdTRUE;
\r
317 /* Raise the priority of the other task so it executes and blocks
\r
318 on the queue again. */
\r
319 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
321 /* The other task should now have re-blocked without exiting the
\r
323 if( xRunIndicator == bktRUN_INDICATOR )
\r
325 /* The other task should not have executed outside of the
\r
327 xErrorOccurred = pdTRUE;
\r
329 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
332 /* Let the other task timeout. When it unblockes it will check that it
\r
333 unblocked at the correct time, then suspend itself. */
\r
334 while( xRunIndicator != bktRUN_INDICATOR )
\r
336 vTaskDelay( bktSHORT_WAIT );
\r
338 vTaskDelay( bktSHORT_WAIT );
\r
343 /*-----------------------------------------------------------*/
\r
345 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
347 portTickType xTimeWhenBlocking, xBlockedTime;
\r
348 portBASE_TYPE xData;
\r
352 /*********************************************************************
\r
355 This task does does not participate in these tests. */
\r
356 vTaskSuspend( NULL );
\r
358 /*********************************************************************
\r
361 The first thing we do is attempt to read from the queue. It should be
\r
362 full so we block. Note the time before we block so we can check the
\r
363 wake time is as per that expected. */
\r
364 portENTER_CRITICAL();
\r
366 xTimeWhenBlocking = xTaskGetTickCount();
\r
368 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
369 anything on the queue. */
\r
371 xRunIndicator = bktRUN_INDICATOR;
\r
372 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
374 xErrorOccurred = pdTRUE;
\r
377 /* How long were we inside the send function? */
\r
378 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
380 portEXIT_CRITICAL();
\r
382 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
383 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
385 xErrorOccurred = pdTRUE;
\r
388 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
389 either. A margin is permitted as we would not necessarily run as
\r
390 soon as we unblocked. */
\r
391 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
393 xErrorOccurred = pdTRUE;
\r
396 /* Suspend ready for test 3. */
\r
397 xRunIndicator = bktRUN_INDICATOR;
\r
398 vTaskSuspend( NULL );
\r
400 /*********************************************************************
\r
403 As per test three, but with the send and receive reversed. */
\r
404 portENTER_CRITICAL();
\r
406 xTimeWhenBlocking = xTaskGetTickCount();
\r
408 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
409 anything on the queue. */
\r
410 xRunIndicator = bktRUN_INDICATOR;
\r
411 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
413 xErrorOccurred = pdTRUE;
\r
416 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
418 portEXIT_CRITICAL();
\r
420 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
421 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
423 xErrorOccurred = pdTRUE;
\r
426 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
427 either. A margin is permitted as we would not necessarily run as soon
\r
428 as we unblocked. */
\r
429 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
431 xErrorOccurred = pdTRUE;
\r
434 xRunIndicator = bktRUN_INDICATOR;
\r
436 xSecondaryCycles++;
\r
439 /*-----------------------------------------------------------*/
\r
441 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
443 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
444 portBASE_TYPE xReturn = pdPASS;
\r
446 /* Have both tasks performed at least one cycle since this function was
\r
448 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
453 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
458 if( xErrorOccurred == pdTRUE )
\r
463 xLastSecondaryCycleCount = xSecondaryCycles;
\r
464 xLastPrimaryCycleCount = xPrimaryCycles;
\r