blob: 56a0b5d893e800c52a5ad515e699f67988c06189 [file] [log] [blame]
Richard Barry86032592007-12-02 18:37:43 +00001/*
Richard Barryc86dcf72008-02-03 19:45:58 +00002 FreeRTOS.org V4.7.1 - Copyright (C) 2003-2008 Richard Barry.
Richard Barry86032592007-12-02 18:37:43 +00003
4 This file is part of the FreeRTOS.org distribution.
5
6 FreeRTOS.org is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 FreeRTOS.org is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with FreeRTOS.org; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 A special exception to the GPL can be applied should you wish to distribute
21 a combined work that includes FreeRTOS.org, without being obliged to provide
22 the source code for any proprietary components. See the licensing section
23 of http://www.FreeRTOS.org for full details of how and when the exception
24 can be applied.
25
26 ***************************************************************************
Richard Barry86032592007-12-02 18:37:43 +000027
Richard Barryc86dcf72008-02-03 19:45:58 +000028 Please ensure to read the configuration and relevant port sections of the
29 online documentation.
30
31 +++ http://www.FreeRTOS.org +++
32 Documentation, latest information, license and contact details.
33
34 +++ http://www.SafeRTOS.com +++
35 A version that is certified for use in safety critical systems.
36
37 +++ http://www.OpenRTOS.com +++
38 Commercial support, development, porting, licensing and training services.
39
Richard Barry86032592007-12-02 18:37:43 +000040 ***************************************************************************
41*/
42
43/*
44 * This is a version of BlockTim.c that uses the light weight API.
45 *
46 * This file contains some test scenarios that ensure tasks do not exit queue
47 * send or receive functions prematurely. A description of the tests is
48 * included within the code.
49 */
50
51/* Kernel includes. */
52#include "FreeRTOS.h"
53#include "task.h"
54#include "queue.h"
55
56/* Demo includes. */
57#include "AltBlock.h"
58
59/* Task priorities. */
60#define bktPRIMARY_PRIORITY ( 3 )
61#define bktSECONDARY_PRIORITY ( 2 )
62
63/* Task behaviour. */
64#define bktQUEUE_LENGTH ( 5 )
65#define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
66#define bktPRIMARY_BLOCK_TIME ( 10 )
67#define bktALLOWABLE_MARGIN ( 12 )
68#define bktTIME_TO_BLOCK ( 175 )
69#define bktDONT_BLOCK ( ( portTickType ) 0 )
70#define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
71
72/* The queue on which the tasks block. */
73static xQueueHandle xTestQueue;
74
75/* Handle to the secondary task is required by the primary task for calls
76to vTaskSuspend/Resume(). */
77static xTaskHandle xSecondary;
78
79/* Used to ensure that tasks are still executing without error. */
80static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
81static portBASE_TYPE xErrorOccurred = pdFALSE;
82
83/* Provides a simple mechanism for the primary task to know when the
84secondary task has executed. */
85static volatile unsigned portBASE_TYPE xRunIndicator;
86
87/* The two test tasks. Their behaviour is commented within the files. */
88static void vPrimaryBlockTimeTestTask( void *pvParameters );
89static void vSecondaryBlockTimeTestTask( void *pvParameters );
90
91/*-----------------------------------------------------------*/
92
93void vCreateAltBlockTimeTasks( void )
94{
95 /* Create the queue on which the two tasks block. */
96 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
97
98 /* Create the two test tasks. */
99 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
100 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
101}
102/*-----------------------------------------------------------*/
103
104static void vPrimaryBlockTimeTestTask( void *pvParameters )
105{
106portBASE_TYPE xItem, xData;
107portTickType xTimeWhenBlocking;
108portTickType xTimeToBlock, xBlockedTime;
109
110 #ifdef USE_STDIO
111 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
112
113 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
114
115 /* Queue a message for printing to say the task has started. */
116 vPrintDisplayMessage( &pcTaskStartMsg );
117 #endif
118
119 ( void ) pvParameters;
120
121 for( ;; )
122 {
123 /*********************************************************************
124 Test 1
125
126 Simple block time wakeup test on queue receives. */
127 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
128 {
129 /* The queue is empty. Attempt to read from the queue using a block
130 time. When we wake, ensure the delta in time is as expected. */
131 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
132
133 /* A critical section is used to minimise the jitter in the time
134 measurements. */
135 portENTER_CRITICAL();
136 {
137 xTimeWhenBlocking = xTaskGetTickCount();
138
139 /* We should unblock after xTimeToBlock having not received
140 anything on the queue. */
141 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
142 {
143 xErrorOccurred = pdTRUE;
144 }
145
146 /* How long were we blocked for? */
147 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
148 }
149 portEXIT_CRITICAL();
150
151 if( xBlockedTime < xTimeToBlock )
152 {
153 /* Should not have blocked for less than we requested. */
154 xErrorOccurred = pdTRUE;
155 }
156
157 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
158 {
159 /* Should not have blocked for longer than we requested,
160 although we would not necessarily run as soon as we were
161 unblocked so a margin is allowed. */
162 xErrorOccurred = pdTRUE;
163 }
164 }
165
Richard Barrye0184222008-01-27 20:25:36 +0000166
167 #if configUSE_PREEMPTION == 0
168 taskYIELD();
169 #endif
170
171
Richard Barry86032592007-12-02 18:37:43 +0000172 /*********************************************************************
173 Test 2
174
175 Simple block time wakeup test on queue sends.
176
177 First fill the queue. It should be empty so all sends should pass. */
178 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
179 {
180 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
181 {
182 xErrorOccurred = pdTRUE;
183 }
184 }
185
186 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
187 {
188 /* The queue is full. Attempt to write to the queue using a block
189 time. When we wake, ensure the delta in time is as expected. */
190 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
191
192 portENTER_CRITICAL();
193 {
194 xTimeWhenBlocking = xTaskGetTickCount();
195
196 /* We should unblock after xTimeToBlock having not received
197 anything on the queue. */
198 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
199 {
200 xErrorOccurred = pdTRUE;
201 }
202
203 /* How long were we blocked for? */
204 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
205 }
206 portEXIT_CRITICAL();
207
208 if( xBlockedTime < xTimeToBlock )
209 {
210 /* Should not have blocked for less than we requested. */
211 xErrorOccurred = pdTRUE;
212 }
213
214 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
215 {
216 /* Should not have blocked for longer than we requested,
217 although we would not necessarily run as soon as we were
218 unblocked so a margin is allowed. */
219 xErrorOccurred = pdTRUE;
220 }
221 }
222
Richard Barrye0184222008-01-27 20:25:36 +0000223 #if configUSE_PREEMPTION == 0
224 taskYIELD();
225 #endif
226
Richard Barry86032592007-12-02 18:37:43 +0000227
228 /*********************************************************************
229 Test 3
230
231 Wake the other task, it will block attempting to post to the queue.
232 When we read from the queue the other task will wake, but before it
233 can run we will post to the queue again. When the other task runs it
234 will find the queue still full, even though it was woken. It should
235 recognise that its block time has not expired and return to block for
236 the remains of its block time.
237
238 Wake the other task so it blocks attempting to post to the already
239 full queue. */
240 xRunIndicator = 0;
241 vTaskResume( xSecondary );
242
243 /* We need to wait a little to ensure the other task executes. */
244 while( xRunIndicator != bktRUN_INDICATOR )
245 {
246 /* The other task has not yet executed. */
247 vTaskDelay( bktSHORT_WAIT );
248 }
249 /* Make sure the other task is blocked on the queue. */
250 vTaskDelay( bktSHORT_WAIT );
251 xRunIndicator = 0;
252
253 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
254 {
255 /* Now when we make space on the queue the other task should wake
256 but not execute as this task has higher priority. */
257 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
258 {
259 xErrorOccurred = pdTRUE;
260 }
261
262 /* Now fill the queue again before the other task gets a chance to
263 execute. If the other task had executed we would find the queue
264 full ourselves, and the other task have set xRunIndicator. */
265 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
266 {
267 xErrorOccurred = pdTRUE;
268 }
269
270 if( xRunIndicator == bktRUN_INDICATOR )
271 {
272 /* The other task should not have executed. */
273 xErrorOccurred = pdTRUE;
274 }
275
276 /* Raise the priority of the other task so it executes and blocks
277 on the queue again. */
278 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
279
280 /* The other task should now have re-blocked without exiting the
281 queue function. */
282 if( xRunIndicator == bktRUN_INDICATOR )
283 {
284 /* The other task should not have executed outside of the
285 queue function. */
286 xErrorOccurred = pdTRUE;
287 }
288
289 /* Set the priority back down. */
290 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
291 }
292
293 /* Let the other task timeout. When it unblockes it will check that it
294 unblocked at the correct time, then suspend itself. */
295 while( xRunIndicator != bktRUN_INDICATOR )
296 {
297 vTaskDelay( bktSHORT_WAIT );
298 }
299 vTaskDelay( bktSHORT_WAIT );
300 xRunIndicator = 0;
301
Richard Barrye0184222008-01-27 20:25:36 +0000302 #if configUSE_PREEMPTION == 0
303 taskYIELD();
304 #endif
Richard Barry86032592007-12-02 18:37:43 +0000305
306 /*********************************************************************
307 Test 4
308
309 As per test 3 - but with the send and receive the other way around.
310 The other task blocks attempting to read from the queue.
311
312 Empty the queue. We should find that it is full. */
313 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
314 {
315 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
316 {
317 xErrorOccurred = pdTRUE;
318 }
319 }
320
321 /* Wake the other task so it blocks attempting to read from the
322 already empty queue. */
323 vTaskResume( xSecondary );
324
325 /* We need to wait a little to ensure the other task executes. */
326 while( xRunIndicator != bktRUN_INDICATOR )
327 {
328 vTaskDelay( bktSHORT_WAIT );
329 }
330 vTaskDelay( bktSHORT_WAIT );
331 xRunIndicator = 0;
332
333 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
334 {
335 /* Now when we place an item on the queue the other task should
336 wake but not execute as this task has higher priority. */
337 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
338 {
339 xErrorOccurred = pdTRUE;
340 }
341
342 /* Now empty the queue again before the other task gets a chance to
343 execute. If the other task had executed we would find the queue
344 empty ourselves, and the other task would be suspended. */
345 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
346 {
347 xErrorOccurred = pdTRUE;
348 }
349
350 if( xRunIndicator == bktRUN_INDICATOR )
351 {
352 /* The other task should not have executed. */
353 xErrorOccurred = pdTRUE;
354 }
355
356 /* Raise the priority of the other task so it executes and blocks
357 on the queue again. */
358 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
359
360 /* The other task should now have re-blocked without exiting the
361 queue function. */
362 if( xRunIndicator == bktRUN_INDICATOR )
363 {
364 /* The other task should not have executed outside of the
365 queue function. */
366 xErrorOccurred = pdTRUE;
367 }
368 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
369 }
370
371 /* Let the other task timeout. When it unblockes it will check that it
372 unblocked at the correct time, then suspend itself. */
373 while( xRunIndicator != bktRUN_INDICATOR )
374 {
375 vTaskDelay( bktSHORT_WAIT );
376 }
377 vTaskDelay( bktSHORT_WAIT );
378
379 xPrimaryCycles++;
380 }
381}
382/*-----------------------------------------------------------*/
383
384static void vSecondaryBlockTimeTestTask( void *pvParameters )
385{
386portTickType xTimeWhenBlocking, xBlockedTime;
387portBASE_TYPE xData;
388
389 #ifdef USE_STDIO
390 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
391
392 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
393
394 /* Queue a message for printing to say the task has started. */
395 vPrintDisplayMessage( &pcTaskStartMsg );
396 #endif
397
398 ( void ) pvParameters;
399
400 for( ;; )
401 {
402 /*********************************************************************
403 Test 1 and 2
404
405 This task does does not participate in these tests. */
406 vTaskSuspend( NULL );
407
408 /*********************************************************************
409 Test 3
410
411 The first thing we do is attempt to read from the queue. It should be
412 full so we block. Note the time before we block so we can check the
413 wake time is as per that expected. */
414 portENTER_CRITICAL();
415 {
416 xTimeWhenBlocking = xTaskGetTickCount();
417
418 /* We should unblock after bktTIME_TO_BLOCK having not received
419 anything on the queue. */
420 xData = 0;
421 xRunIndicator = bktRUN_INDICATOR;
422 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
423 {
424 xErrorOccurred = pdTRUE;
425 }
426
427 /* How long were we inside the send function? */
428 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
429 }
430 portEXIT_CRITICAL();
431
432 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
433 if( xBlockedTime < bktTIME_TO_BLOCK )
434 {
435 xErrorOccurred = pdTRUE;
436 }
437
438 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
439 either. A margin is permitted as we would not necessarily run as
440 soon as we unblocked. */
441 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
442 {
443 xErrorOccurred = pdTRUE;
444 }
445
446 /* Suspend ready for test 3. */
447 xRunIndicator = bktRUN_INDICATOR;
448 vTaskSuspend( NULL );
449
450 /*********************************************************************
451 Test 4
452
453 As per test three, but with the send and receive reversed. */
454 portENTER_CRITICAL();
455 {
456 xTimeWhenBlocking = xTaskGetTickCount();
457
458 /* We should unblock after bktTIME_TO_BLOCK having not received
459 anything on the queue. */
460 xRunIndicator = bktRUN_INDICATOR;
461 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
462 {
463 xErrorOccurred = pdTRUE;
464 }
465
466 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
467 }
468 portEXIT_CRITICAL();
469
470 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
471 if( xBlockedTime < bktTIME_TO_BLOCK )
472 {
473 xErrorOccurred = pdTRUE;
474 }
475
476 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
477 either. A margin is permitted as we would not necessarily run as soon
478 as we unblocked. */
479 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
480 {
481 xErrorOccurred = pdTRUE;
482 }
483
484 xRunIndicator = bktRUN_INDICATOR;
485
486 xSecondaryCycles++;
487 }
488}
489/*-----------------------------------------------------------*/
490
491portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
492{
493static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
494portBASE_TYPE xReturn = pdPASS;
495
496 /* Have both tasks performed at least one cycle since this function was
497 last called? */
498 if( xPrimaryCycles == xLastPrimaryCycleCount )
499 {
500 xReturn = pdFAIL;
501 }
502
503 if( xSecondaryCycles == xLastSecondaryCycleCount )
504 {
505 xReturn = pdFAIL;
506 }
507
508 if( xErrorOccurred == pdTRUE )
509 {
510 xReturn = pdFAIL;
511 }
512
513 xLastSecondaryCycleCount = xSecondaryCycles;
514 xLastPrimaryCycleCount = xPrimaryCycles;
515
516 return xReturn;
517}