]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/blocktim.c
e87ab09dc3420c30aa915e46552e8a400bf0eedc
[freertos] / FreeRTOS / Demo / Common / Minimal / blocktim.c
1 /*\r
2     FreeRTOS V8.1.1 - Copyright (C) 2014 Real Time Engineers Ltd. \r
3     All rights reserved\r
4 \r
5     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.\r
6 \r
7     ***************************************************************************\r
8      *                                                                       *\r
9      *    FreeRTOS provides completely free yet professionally developed,    *\r
10      *    robust, strictly quality controlled, supported, and cross          *\r
11      *    platform software that has become a de facto standard.             *\r
12      *                                                                       *\r
13      *    Help yourself get started quickly and support the FreeRTOS         *\r
14      *    project by purchasing a FreeRTOS tutorial book, reference          *\r
15      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *\r
16      *                                                                       *\r
17      *    Thank you!                                                         *\r
18      *                                                                       *\r
19     ***************************************************************************\r
20 \r
21     This file is part of the FreeRTOS distribution.\r
22 \r
23     FreeRTOS is free software; you can redistribute it and/or modify it under\r
24     the terms of the GNU General Public License (version 2) as published by the\r
25     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.\r
26 \r
27     >>!   NOTE: The modification to the GPL is included to allow you to     !<<\r
28     >>!   distribute a combined work that includes FreeRTOS without being   !<<\r
29     >>!   obliged to provide the source code for proprietary components     !<<\r
30     >>!   outside of the FreeRTOS kernel.                                   !<<\r
31 \r
32     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY\r
33     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
34     FOR A PARTICULAR PURPOSE.  Full license text is available from the following\r
35     link: http://www.freertos.org/a00114.html\r
36 \r
37     1 tab == 4 spaces!\r
38 \r
39     ***************************************************************************\r
40      *                                                                       *\r
41      *    Having a problem?  Start by reading the FAQ "My application does   *\r
42      *    not run, what could be wrong?"                                     *\r
43      *                                                                       *\r
44      *    http://www.FreeRTOS.org/FAQHelp.html                               *\r
45      *                                                                       *\r
46     ***************************************************************************\r
47 \r
48     http://www.FreeRTOS.org - Documentation, books, training, latest versions,\r
49     license and Real Time Engineers Ltd. contact details.\r
50 \r
51     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,\r
52     including FreeRTOS+Trace - an indispensable productivity tool, a DOS\r
53     compatible FAT file system, and our tiny thread aware UDP/IP stack.\r
54 \r
55     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High\r
56     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS\r
57     licenses offer ticketed support, indemnification and middleware.\r
58 \r
59     http://www.SafeRTOS.com - High Integrity Systems also provide a safety\r
60     engineered and independently SIL3 certified version for use in safety and\r
61     mission critical applications that require provable dependability.\r
62 \r
63     1 tab == 4 spaces!\r
64 */\r
65 \r
66 /*\r
67  * This file contains some test scenarios that ensure tasks do not exit queue\r
68  * send or receive functions prematurely.  A description of the tests is\r
69  * included within the code.\r
70  */\r
71 \r
72 /* Kernel includes. */\r
73 #include "FreeRTOS.h"\r
74 #include "task.h"\r
75 #include "queue.h"\r
76 \r
77 /* Demo includes. */\r
78 #include "blocktim.h"\r
79 \r
80 /* Task priorities.  Allow these to be overridden. */\r
81 #ifndef bktPRIMARY_PRIORITY\r
82         #define bktPRIMARY_PRIORITY             ( configMAX_PRIORITIES - 3 )\r
83 #endif\r
84 \r
85 #ifndef bktSECONDARY_PRIORITY\r
86         #define bktSECONDARY_PRIORITY   ( configMAX_PRIORITIES - 4 )\r
87 #endif\r
88 \r
89 /* Task behaviour. */\r
90 #define bktQUEUE_LENGTH                         ( 5 )\r
91 #define bktSHORT_WAIT                           ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )\r
92 #define bktPRIMARY_BLOCK_TIME           ( 10 )\r
93 #define bktALLOWABLE_MARGIN                     ( 15 )\r
94 #define bktTIME_TO_BLOCK                        ( 175 )\r
95 #define bktDONT_BLOCK                           ( ( TickType_t ) 0 )\r
96 #define bktRUN_INDICATOR                        ( ( UBaseType_t ) 0x55 )\r
97 \r
98 /* The queue on which the tasks block. */\r
99 static QueueHandle_t xTestQueue;\r
100 \r
101 /* Handle to the secondary task is required by the primary task for calls\r
102 to vTaskSuspend/Resume(). */\r
103 static TaskHandle_t xSecondary;\r
104 \r
105 /* Used to ensure that tasks are still executing without error. */\r
106 static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;\r
107 static volatile BaseType_t xErrorOccurred = pdFALSE;\r
108 \r
109 /* Provides a simple mechanism for the primary task to know when the\r
110 secondary task has executed. */\r
111 static volatile UBaseType_t xRunIndicator;\r
112 \r
113 /* The two test tasks.  Their behaviour is commented within the files. */\r
114 static void vPrimaryBlockTimeTestTask( void *pvParameters );\r
115 static void vSecondaryBlockTimeTestTask( void *pvParameters );\r
116 \r
117 /*-----------------------------------------------------------*/\r
118 \r
119 void vCreateBlockTimeTasks( void )\r
120 {\r
121         /* Create the queue on which the two tasks block. */\r
122     xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );\r
123 \r
124         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
125         in use.  The queue registry is provided as a means for kernel aware\r
126         debuggers to locate queues and has no purpose if a kernel aware debugger\r
127         is not being used.  The call to vQueueAddToRegistry() will be removed\r
128         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
129         defined to be less than 1. */\r
130         vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );\r
131 \r
132         /* Create the two test tasks. */\r
133         xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );\r
134         xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );\r
135 }\r
136 /*-----------------------------------------------------------*/\r
137 \r
138 static void vPrimaryBlockTimeTestTask( void *pvParameters )\r
139 {\r
140 BaseType_t xItem, xData;\r
141 TickType_t xTimeWhenBlocking;\r
142 TickType_t xTimeToBlock, xBlockedTime;\r
143 \r
144         ( void ) pvParameters;\r
145 \r
146         for( ;; )\r
147         {\r
148                 /*********************************************************************\r
149         Test 1\r
150 \r
151         Simple block time wakeup test on queue receives. */\r
152                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
153                 {\r
154                         /* The queue is empty. Attempt to read from the queue using a block\r
155                         time.  When we wake, ensure the delta in time is as expected. */\r
156                         xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );\r
157 \r
158                         xTimeWhenBlocking = xTaskGetTickCount();\r
159 \r
160                         /* We should unblock after xTimeToBlock having not received\r
161                         anything on the queue. */\r
162                         if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )\r
163                         {\r
164                                 xErrorOccurred = pdTRUE;\r
165                         }\r
166 \r
167                         /* How long were we blocked for? */\r
168                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
169 \r
170                         if( xBlockedTime < xTimeToBlock )\r
171                         {\r
172                                 /* Should not have blocked for less than we requested. */\r
173                                 xErrorOccurred = pdTRUE;\r
174                         }\r
175 \r
176                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
177                         {\r
178                                 /* Should not have blocked for longer than we requested,\r
179                                 although we would not necessarily run as soon as we were\r
180                                 unblocked so a margin is allowed. */\r
181                                 xErrorOccurred = pdTRUE;\r
182                         }\r
183                 }\r
184 \r
185                 /*********************************************************************\r
186         Test 2\r
187 \r
188         Simple block time wakeup test on queue sends.\r
189 \r
190                 First fill the queue.  It should be empty so all sends should pass. */\r
191                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
192                 {\r
193                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
194                         {\r
195                                 xErrorOccurred = pdTRUE;\r
196                         }\r
197 \r
198                         #if configUSE_PREEMPTION == 0\r
199                                 taskYIELD();\r
200                         #endif\r
201                 }\r
202 \r
203                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
204                 {\r
205                         /* The queue is full. Attempt to write to the queue using a block\r
206                         time.  When we wake, ensure the delta in time is as expected. */\r
207                         xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );\r
208 \r
209                         xTimeWhenBlocking = xTaskGetTickCount();\r
210 \r
211                         /* We should unblock after xTimeToBlock having not received\r
212                         anything on the queue. */\r
213                         if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )\r
214                         {\r
215                                 xErrorOccurred = pdTRUE;\r
216                         }\r
217 \r
218                         /* How long were we blocked for? */\r
219                         xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
220 \r
221                         if( xBlockedTime < xTimeToBlock )\r
222                         {\r
223                                 /* Should not have blocked for less than we requested. */\r
224                                 xErrorOccurred = pdTRUE;\r
225                         }\r
226 \r
227                         if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )\r
228                         {\r
229                                 /* Should not have blocked for longer than we requested,\r
230                                 although we would not necessarily run as soon as we were\r
231                                 unblocked so a margin is allowed. */\r
232                                 xErrorOccurred = pdTRUE;\r
233                         }\r
234                 }\r
235 \r
236                 /*********************************************************************\r
237         Test 3\r
238 \r
239                 Wake the other task, it will block attempting to post to the queue.\r
240                 When we read from the queue the other task will wake, but before it\r
241                 can run we will post to the queue again.  When the other task runs it\r
242                 will find the queue still full, even though it was woken.  It should\r
243                 recognise that its block time has not expired and return to block for\r
244                 the remains of its block time.\r
245 \r
246                 Wake the other task so it blocks attempting to post to the already\r
247                 full queue. */\r
248                 xRunIndicator = 0;\r
249                 vTaskResume( xSecondary );\r
250 \r
251                 /* We need to wait a little to ensure the other task executes. */\r
252                 while( xRunIndicator != bktRUN_INDICATOR )\r
253                 {\r
254                         /* The other task has not yet executed. */\r
255                         vTaskDelay( bktSHORT_WAIT );\r
256                 }\r
257                 /* Make sure the other task is blocked on the queue. */\r
258                 vTaskDelay( bktSHORT_WAIT );\r
259                 xRunIndicator = 0;\r
260 \r
261                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
262                 {\r
263                         /* Now when we make space on the queue the other task should wake\r
264                         but not execute as this task has higher priority. */\r
265                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
266                         {\r
267                                 xErrorOccurred = pdTRUE;\r
268                         }\r
269 \r
270                         /* Now fill the queue again before the other task gets a chance to\r
271                         execute.  If the other task had executed we would find the queue\r
272                         full ourselves, and the other task have set xRunIndicator. */\r
273                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
274                         {\r
275                                 xErrorOccurred = pdTRUE;\r
276                         }\r
277 \r
278                         if( xRunIndicator == bktRUN_INDICATOR )\r
279                         {\r
280                                 /* The other task should not have executed. */\r
281                                 xErrorOccurred = pdTRUE;\r
282                         }\r
283 \r
284                         /* Raise the priority of the other task so it executes and blocks\r
285                         on the queue again. */\r
286                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
287 \r
288                         /* The other task should now have re-blocked without exiting the\r
289                         queue function. */\r
290                         if( xRunIndicator == bktRUN_INDICATOR )\r
291                         {\r
292                                 /* The other task should not have executed outside of the\r
293                                 queue function. */\r
294                                 xErrorOccurred = pdTRUE;\r
295                         }\r
296 \r
297                         /* Set the priority back down. */\r
298                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
299                 }\r
300 \r
301                 /* Let the other task timeout.  When it unblockes it will check that it\r
302                 unblocked at the correct time, then suspend itself. */\r
303                 while( xRunIndicator != bktRUN_INDICATOR )\r
304                 {\r
305                         vTaskDelay( bktSHORT_WAIT );\r
306                 }\r
307                 vTaskDelay( bktSHORT_WAIT );\r
308                 xRunIndicator = 0;\r
309 \r
310 \r
311                 /*********************************************************************\r
312         Test 4\r
313 \r
314                 As per test 3 - but with the send and receive the other way around.\r
315                 The other task blocks attempting to read from the queue.\r
316 \r
317                 Empty the queue.  We should find that it is full. */\r
318                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
319                 {\r
320                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
321                         {\r
322                                 xErrorOccurred = pdTRUE;\r
323                         }\r
324                 }\r
325 \r
326                 /* Wake the other task so it blocks attempting to read from  the\r
327                 already empty queue. */\r
328                 vTaskResume( xSecondary );\r
329 \r
330                 /* We need to wait a little to ensure the other task executes. */\r
331                 while( xRunIndicator != bktRUN_INDICATOR )\r
332                 {\r
333                         vTaskDelay( bktSHORT_WAIT );\r
334                 }\r
335                 vTaskDelay( bktSHORT_WAIT );\r
336                 xRunIndicator = 0;\r
337 \r
338                 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )\r
339                 {\r
340                         /* Now when we place an item on the queue the other task should\r
341                         wake but not execute as this task has higher priority. */\r
342                         if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )\r
343                         {\r
344                                 xErrorOccurred = pdTRUE;\r
345                         }\r
346 \r
347                         /* Now empty the queue again before the other task gets a chance to\r
348                         execute.  If the other task had executed we would find the queue\r
349                         empty ourselves, and the other task would be suspended. */\r
350                         if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )\r
351                         {\r
352                                 xErrorOccurred = pdTRUE;\r
353                         }\r
354 \r
355                         if( xRunIndicator == bktRUN_INDICATOR )\r
356                         {\r
357                                 /* The other task should not have executed. */\r
358                                 xErrorOccurred = pdTRUE;\r
359                         }\r
360 \r
361                         /* Raise the priority of the other task so it executes and blocks\r
362                         on the queue again. */\r
363                         vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );\r
364 \r
365                         /* The other task should now have re-blocked without exiting the\r
366                         queue function. */\r
367                         if( xRunIndicator == bktRUN_INDICATOR )\r
368                         {\r
369                                 /* The other task should not have executed outside of the\r
370                                 queue function. */\r
371                                 xErrorOccurred = pdTRUE;\r
372                         }\r
373                         vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );\r
374                 }\r
375 \r
376                 /* Let the other task timeout.  When it unblockes it will check that it\r
377                 unblocked at the correct time, then suspend itself. */\r
378                 while( xRunIndicator != bktRUN_INDICATOR )\r
379                 {\r
380                         vTaskDelay( bktSHORT_WAIT );\r
381                 }\r
382                 vTaskDelay( bktSHORT_WAIT );\r
383 \r
384                 xPrimaryCycles++;\r
385         }\r
386 }\r
387 /*-----------------------------------------------------------*/\r
388 \r
389 static void vSecondaryBlockTimeTestTask( void *pvParameters )\r
390 {\r
391 TickType_t xTimeWhenBlocking, xBlockedTime;\r
392 BaseType_t xData;\r
393 \r
394         ( void ) pvParameters;\r
395 \r
396         for( ;; )\r
397         {\r
398                 /*********************************************************************\r
399         Test 1 and 2\r
400 \r
401                 This task does does not participate in these tests. */\r
402                 vTaskSuspend( NULL );\r
403 \r
404                 /*********************************************************************\r
405         Test 3\r
406 \r
407                 The first thing we do is attempt to read from the queue.  It should be\r
408                 full so we block.  Note the time before we block so we can check the\r
409                 wake time is as per that expected. */\r
410                 xTimeWhenBlocking = xTaskGetTickCount();\r
411 \r
412                 /* We should unblock after bktTIME_TO_BLOCK having not sent\r
413                 anything to the queue. */\r
414                 xData = 0;\r
415                 xRunIndicator = bktRUN_INDICATOR;\r
416                 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )\r
417                 {\r
418                         xErrorOccurred = pdTRUE;\r
419                 }\r
420 \r
421                 /* How long were we inside the send function? */\r
422                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
423 \r
424                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
425                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
426                 {\r
427                         xErrorOccurred = pdTRUE;\r
428                 }\r
429 \r
430                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
431                 either.  A margin is permitted as we would not necessarily run as\r
432                 soon as we unblocked. */\r
433                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
434                 {\r
435                         xErrorOccurred = pdTRUE;\r
436                 }\r
437 \r
438                 /* Suspend ready for test 3. */\r
439                 xRunIndicator = bktRUN_INDICATOR;\r
440                 vTaskSuspend( NULL );\r
441 \r
442                 /*********************************************************************\r
443         Test 4\r
444 \r
445                 As per test three, but with the send and receive reversed. */\r
446                 xTimeWhenBlocking = xTaskGetTickCount();\r
447 \r
448                 /* We should unblock after bktTIME_TO_BLOCK having not received\r
449                 anything on the queue. */\r
450                 xRunIndicator = bktRUN_INDICATOR;\r
451                 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )\r
452                 {\r
453                         xErrorOccurred = pdTRUE;\r
454                 }\r
455 \r
456                 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;\r
457 \r
458                 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */\r
459                 if( xBlockedTime < bktTIME_TO_BLOCK )\r
460                 {\r
461                         xErrorOccurred = pdTRUE;\r
462                 }\r
463 \r
464                 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN\r
465                 either.  A margin is permitted as we would not necessarily run as soon\r
466                 as we unblocked. */\r
467                 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )\r
468                 {\r
469                         xErrorOccurred = pdTRUE;\r
470                 }\r
471 \r
472                 xRunIndicator = bktRUN_INDICATOR;\r
473 \r
474                 xSecondaryCycles++;\r
475         }\r
476 }\r
477 /*-----------------------------------------------------------*/\r
478 \r
479 BaseType_t xAreBlockTimeTestTasksStillRunning( void )\r
480 {\r
481 static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;\r
482 BaseType_t xReturn = pdPASS;\r
483 \r
484         /* Have both tasks performed at least one cycle since this function was\r
485         last called? */\r
486         if( xPrimaryCycles == xLastPrimaryCycleCount )\r
487         {\r
488                 xReturn = pdFAIL;\r
489         }\r
490 \r
491         if( xSecondaryCycles == xLastSecondaryCycleCount )\r
492         {\r
493                 xReturn = pdFAIL;\r
494         }\r
495 \r
496         if( xErrorOccurred == pdTRUE )\r
497         {\r
498                 xReturn = pdFAIL;\r
499         }\r
500 \r
501         xLastSecondaryCycleCount = xSecondaryCycles;\r
502         xLastPrimaryCycleCount = xPrimaryCycles;\r
503 \r
504         return xReturn;\r
505 }\r