root/webserver/example/freeRTOS/Demo/Common/Minimal/blocktim.c

Revision 14, 15.6 kB (checked in by phil, 15 years ago)

added unmodified FreeRTOS package V5.4.1 with only web srv demo source for LPC2368 for CrossWorks?

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