FreeRTOS Real Time Operating System, Modified from Kenji Arai's initial port. See freertos.org for full documentation.
Fork of FreeRTOS_on_mbed_v1 by
blocktim.c
00001 /* 00002 FreeRTOS V6.0.3 - Copyright (C) 2010 Real Time Engineers Ltd. 00003 00004 *************************************************************************** 00005 * * 00006 * If you are: * 00007 * * 00008 * + New to FreeRTOS, * 00009 * + Wanting to learn FreeRTOS or multitasking in general quickly * 00010 * + Looking for basic training, * 00011 * + Wanting to improve your FreeRTOS skills and productivity * 00012 * * 00013 * then take a look at the FreeRTOS eBook * 00014 * * 00015 * "Using the FreeRTOS Real Time Kernel - a Practical Guide" * 00016 * http://www.FreeRTOS.org/Documentation * 00017 * * 00018 * A pdf reference manual is also available. Both are usually delivered * 00019 * to your inbox within 20 minutes to two hours when purchased between 8am * 00020 * and 8pm GMT (although please allow up to 24 hours in case of * 00021 * exceptional circumstances). Thank you for your support! * 00022 * * 00023 *************************************************************************** 00024 00025 This file is part of the FreeRTOS distribution. 00026 00027 FreeRTOS is free software; you can redistribute it and/or modify it under 00028 the terms of the GNU General Public License (version 2) as published by the 00029 Free Software Foundation AND MODIFIED BY the FreeRTOS exception. 00030 ***NOTE*** The exception to the GPL is included to allow you to distribute 00031 a combined work that includes FreeRTOS without being obliged to provide the 00032 source code for proprietary components outside of the FreeRTOS kernel. 00033 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT 00034 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00035 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 00036 more details. You should have received a copy of the GNU General Public 00037 License and the FreeRTOS license exception along with FreeRTOS; if not it 00038 can be viewed here: http://www.freertos.org/a00114.html and also obtained 00039 by writing to Richard Barry, contact details for whom are available on the 00040 FreeRTOS WEB site. 00041 00042 1 tab == 4 spaces! 00043 00044 http://www.FreeRTOS.org - Documentation, latest information, license and 00045 contact details. 00046 00047 http://www.SafeRTOS.com - A version that is certified for use in safety 00048 critical systems. 00049 00050 http://www.OpenRTOS.com - Commercial support, development, porting, 00051 licensing and training services. 00052 */ 00053 00054 /* 00055 * This file contains some test scenarios that ensure tasks do not exit queue 00056 * send or receive functions prematurely. A description of the tests is 00057 * included within the code. 00058 */ 00059 00060 /* Kernel includes. */ 00061 #include "FreeRTOS.h" 00062 #include "task.h" 00063 #include "queue.h" 00064 00065 /* Demo includes. */ 00066 #include "blocktim.h" 00067 00068 /* Task priorities. Allow these to be overridden. */ 00069 #ifndef bktPRIMARY_PRIORITY 00070 #define bktPRIMARY_PRIORITY ( 3 ) 00071 #endif 00072 00073 #ifndef bktSECONDARY_PRIORITY 00074 #define bktSECONDARY_PRIORITY ( 2 ) 00075 #endif 00076 00077 /* Task behaviour. */ 00078 #define bktQUEUE_LENGTH ( 5 ) 00079 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS ) 00080 #define bktPRIMARY_BLOCK_TIME ( 10 ) 00081 #define bktALLOWABLE_MARGIN ( 15 ) 00082 #define bktTIME_TO_BLOCK ( 175 ) 00083 #define bktDONT_BLOCK ( ( portTickType ) 0 ) 00084 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 ) 00085 00086 /* The queue on which the tasks block. */ 00087 static xQueueHandle xTestQueue; 00088 00089 /* Handle to the secondary task is required by the primary task for calls 00090 to vTaskSuspend/Resume(). */ 00091 static xTaskHandle xSecondary; 00092 00093 /* Used to ensure that tasks are still executing without error. */ 00094 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0; 00095 static volatile portBASE_TYPE xErrorOccurred = pdFALSE; 00096 00097 /* Provides a simple mechanism for the primary task to know when the 00098 secondary task has executed. */ 00099 static volatile unsigned portBASE_TYPE xRunIndicator; 00100 00101 /* The two test tasks. Their behaviour is commented within the files. */ 00102 static void vPrimaryBlockTimeTestTask( void *pvParameters ); 00103 static void vSecondaryBlockTimeTestTask( void *pvParameters ); 00104 00105 /*-----------------------------------------------------------*/ 00106 00107 void vCreateBlockTimeTasks( void ) 00108 { 00109 /* Create the queue on which the two tasks block. */ 00110 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) ); 00111 00112 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is 00113 in use. The queue registry is provided as a means for kernel aware 00114 debuggers to locate queues and has no purpose if a kernel aware debugger 00115 is not being used. The call to vQueueAddToRegistry() will be removed 00116 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 00117 defined to be less than 1. */ 00118 vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" ); 00119 00120 /* Create the two test tasks. */ 00121 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL ); 00122 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary ); 00123 } 00124 /*-----------------------------------------------------------*/ 00125 00126 static void vPrimaryBlockTimeTestTask( void *pvParameters ) 00127 { 00128 portBASE_TYPE xItem, xData; 00129 portTickType xTimeWhenBlocking; 00130 portTickType xTimeToBlock, xBlockedTime; 00131 00132 ( void ) pvParameters; 00133 00134 for( ;; ) 00135 { 00136 /********************************************************************* 00137 Test 1 00138 00139 Simple block time wakeup test on queue receives. */ 00140 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) 00141 { 00142 /* The queue is empty. Attempt to read from the queue using a block 00143 time. When we wake, ensure the delta in time is as expected. */ 00144 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem; 00145 00146 xTimeWhenBlocking = xTaskGetTickCount(); 00147 00148 /* We should unblock after xTimeToBlock having not received 00149 anything on the queue. */ 00150 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY ) 00151 { 00152 xErrorOccurred = pdTRUE; 00153 } 00154 00155 /* How long were we blocked for? */ 00156 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; 00157 00158 if( xBlockedTime < xTimeToBlock ) 00159 { 00160 /* Should not have blocked for less than we requested. */ 00161 xErrorOccurred = pdTRUE; 00162 } 00163 00164 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) 00165 { 00166 /* Should not have blocked for longer than we requested, 00167 although we would not necessarily run as soon as we were 00168 unblocked so a margin is allowed. */ 00169 xErrorOccurred = pdTRUE; 00170 } 00171 } 00172 00173 /********************************************************************* 00174 Test 2 00175 00176 Simple block time wakeup test on queue sends. 00177 00178 First fill the queue. It should be empty so all sends should pass. */ 00179 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) 00180 { 00181 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) 00182 { 00183 xErrorOccurred = pdTRUE; 00184 } 00185 00186 #if configUSE_PREEMPTION == 0 00187 taskYIELD(); 00188 #endif 00189 } 00190 00191 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) 00192 { 00193 /* The queue is full. Attempt to write to the queue using a block 00194 time. When we wake, ensure the delta in time is as expected. */ 00195 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem; 00196 00197 xTimeWhenBlocking = xTaskGetTickCount(); 00198 00199 /* We should unblock after xTimeToBlock having not received 00200 anything on the queue. */ 00201 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL ) 00202 { 00203 xErrorOccurred = pdTRUE; 00204 } 00205 00206 /* How long were we blocked for? */ 00207 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; 00208 00209 if( xBlockedTime < xTimeToBlock ) 00210 { 00211 /* Should not have blocked for less than we requested. */ 00212 xErrorOccurred = pdTRUE; 00213 } 00214 00215 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) 00216 { 00217 /* Should not have blocked for longer than we requested, 00218 although we would not necessarily run as soon as we were 00219 unblocked so a margin is allowed. */ 00220 xErrorOccurred = pdTRUE; 00221 } 00222 } 00223 00224 /********************************************************************* 00225 Test 3 00226 00227 Wake the other task, it will block attempting to post to the queue. 00228 When we read from the queue the other task will wake, but before it 00229 can run we will post to the queue again. When the other task runs it 00230 will find the queue still full, even though it was woken. It should 00231 recognise that its block time has not expired and return to block for 00232 the remains of its block time. 00233 00234 Wake the other task so it blocks attempting to post to the already 00235 full queue. */ 00236 xRunIndicator = 0; 00237 vTaskResume( xSecondary ); 00238 00239 /* We need to wait a little to ensure the other task executes. */ 00240 while( xRunIndicator != bktRUN_INDICATOR ) 00241 { 00242 /* The other task has not yet executed. */ 00243 vTaskDelay( bktSHORT_WAIT ); 00244 } 00245 /* Make sure the other task is blocked on the queue. */ 00246 vTaskDelay( bktSHORT_WAIT ); 00247 xRunIndicator = 0; 00248 00249 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) 00250 { 00251 /* Now when we make space on the queue the other task should wake 00252 but not execute as this task has higher priority. */ 00253 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) 00254 { 00255 xErrorOccurred = pdTRUE; 00256 } 00257 00258 /* Now fill the queue again before the other task gets a chance to 00259 execute. If the other task had executed we would find the queue 00260 full ourselves, and the other task have set xRunIndicator. */ 00261 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) 00262 { 00263 xErrorOccurred = pdTRUE; 00264 } 00265 00266 if( xRunIndicator == bktRUN_INDICATOR ) 00267 { 00268 /* The other task should not have executed. */ 00269 xErrorOccurred = pdTRUE; 00270 } 00271 00272 /* Raise the priority of the other task so it executes and blocks 00273 on the queue again. */ 00274 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); 00275 00276 /* The other task should now have re-blocked without exiting the 00277 queue function. */ 00278 if( xRunIndicator == bktRUN_INDICATOR ) 00279 { 00280 /* The other task should not have executed outside of the 00281 queue function. */ 00282 xErrorOccurred = pdTRUE; 00283 } 00284 00285 /* Set the priority back down. */ 00286 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY ); 00287 } 00288 00289 /* Let the other task timeout. When it unblockes it will check that it 00290 unblocked at the correct time, then suspend itself. */ 00291 while( xRunIndicator != bktRUN_INDICATOR ) 00292 { 00293 vTaskDelay( bktSHORT_WAIT ); 00294 } 00295 vTaskDelay( bktSHORT_WAIT ); 00296 xRunIndicator = 0; 00297 00298 00299 /********************************************************************* 00300 Test 4 00301 00302 As per test 3 - but with the send and receive the other way around. 00303 The other task blocks attempting to read from the queue. 00304 00305 Empty the queue. We should find that it is full. */ 00306 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) 00307 { 00308 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) 00309 { 00310 xErrorOccurred = pdTRUE; 00311 } 00312 } 00313 00314 /* Wake the other task so it blocks attempting to read from the 00315 already empty queue. */ 00316 vTaskResume( xSecondary ); 00317 00318 /* We need to wait a little to ensure the other task executes. */ 00319 while( xRunIndicator != bktRUN_INDICATOR ) 00320 { 00321 vTaskDelay( bktSHORT_WAIT ); 00322 } 00323 vTaskDelay( bktSHORT_WAIT ); 00324 xRunIndicator = 0; 00325 00326 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) 00327 { 00328 /* Now when we place an item on the queue the other task should 00329 wake but not execute as this task has higher priority. */ 00330 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) 00331 { 00332 xErrorOccurred = pdTRUE; 00333 } 00334 00335 /* Now empty the queue again before the other task gets a chance to 00336 execute. If the other task had executed we would find the queue 00337 empty ourselves, and the other task would be suspended. */ 00338 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) 00339 { 00340 xErrorOccurred = pdTRUE; 00341 } 00342 00343 if( xRunIndicator == bktRUN_INDICATOR ) 00344 { 00345 /* The other task should not have executed. */ 00346 xErrorOccurred = pdTRUE; 00347 } 00348 00349 /* Raise the priority of the other task so it executes and blocks 00350 on the queue again. */ 00351 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); 00352 00353 /* The other task should now have re-blocked without exiting the 00354 queue function. */ 00355 if( xRunIndicator == bktRUN_INDICATOR ) 00356 { 00357 /* The other task should not have executed outside of the 00358 queue function. */ 00359 xErrorOccurred = pdTRUE; 00360 } 00361 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY ); 00362 } 00363 00364 /* Let the other task timeout. When it unblockes it will check that it 00365 unblocked at the correct time, then suspend itself. */ 00366 while( xRunIndicator != bktRUN_INDICATOR ) 00367 { 00368 vTaskDelay( bktSHORT_WAIT ); 00369 } 00370 vTaskDelay( bktSHORT_WAIT ); 00371 00372 xPrimaryCycles++; 00373 } 00374 } 00375 /*-----------------------------------------------------------*/ 00376 00377 static void vSecondaryBlockTimeTestTask( void *pvParameters ) 00378 { 00379 portTickType xTimeWhenBlocking, xBlockedTime; 00380 portBASE_TYPE xData; 00381 00382 ( void ) pvParameters; 00383 00384 for( ;; ) 00385 { 00386 /********************************************************************* 00387 Test 1 and 2 00388 00389 This task does does not participate in these tests. */ 00390 vTaskSuspend( NULL ); 00391 00392 /********************************************************************* 00393 Test 3 00394 00395 The first thing we do is attempt to read from the queue. It should be 00396 full so we block. Note the time before we block so we can check the 00397 wake time is as per that expected. */ 00398 xTimeWhenBlocking = xTaskGetTickCount(); 00399 00400 /* We should unblock after bktTIME_TO_BLOCK having not sent 00401 anything to the queue. */ 00402 xData = 0; 00403 xRunIndicator = bktRUN_INDICATOR; 00404 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL ) 00405 { 00406 xErrorOccurred = pdTRUE; 00407 } 00408 00409 /* How long were we inside the send function? */ 00410 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; 00411 00412 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */ 00413 if( xBlockedTime < bktTIME_TO_BLOCK ) 00414 { 00415 xErrorOccurred = pdTRUE; 00416 } 00417 00418 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN 00419 either. A margin is permitted as we would not necessarily run as 00420 soon as we unblocked. */ 00421 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) ) 00422 { 00423 xErrorOccurred = pdTRUE; 00424 } 00425 00426 /* Suspend ready for test 3. */ 00427 xRunIndicator = bktRUN_INDICATOR; 00428 vTaskSuspend( NULL ); 00429 00430 /********************************************************************* 00431 Test 4 00432 00433 As per test three, but with the send and receive reversed. */ 00434 xTimeWhenBlocking = xTaskGetTickCount(); 00435 00436 /* We should unblock after bktTIME_TO_BLOCK having not received 00437 anything on the queue. */ 00438 xRunIndicator = bktRUN_INDICATOR; 00439 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY ) 00440 { 00441 xErrorOccurred = pdTRUE; 00442 } 00443 00444 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking; 00445 00446 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */ 00447 if( xBlockedTime < bktTIME_TO_BLOCK ) 00448 { 00449 xErrorOccurred = pdTRUE; 00450 } 00451 00452 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN 00453 either. A margin is permitted as we would not necessarily run as soon 00454 as we unblocked. */ 00455 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) ) 00456 { 00457 xErrorOccurred = pdTRUE; 00458 } 00459 00460 xRunIndicator = bktRUN_INDICATOR; 00461 00462 xSecondaryCycles++; 00463 } 00464 } 00465 /*-----------------------------------------------------------*/ 00466 00467 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void ) 00468 { 00469 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0; 00470 portBASE_TYPE xReturn = pdPASS; 00471 00472 /* Have both tasks performed at least one cycle since this function was 00473 last called? */ 00474 if( xPrimaryCycles == xLastPrimaryCycleCount ) 00475 { 00476 xReturn = pdFAIL; 00477 } 00478 00479 if( xSecondaryCycles == xLastSecondaryCycleCount ) 00480 { 00481 xReturn = pdFAIL; 00482 } 00483 00484 if( xErrorOccurred == pdTRUE ) 00485 { 00486 xReturn = pdFAIL; 00487 } 00488 00489 xLastSecondaryCycleCount = xSecondaryCycles; 00490 xLastPrimaryCycleCount = xPrimaryCycles; 00491 00492 return xReturn; 00493 }
Generated on Fri Jul 15 2022 10:21:25 by
1.7.2
