root/webserver/example/freeRTOS/Demo/Common/Full/dynamic.c

Revision 14, 20.9 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  * The first test creates three tasks - two counter tasks (one continuous count
50  * and one limited count) and one controller.  A "count" variable is shared
51  * between all three tasks.  The two counter tasks should never be in a "ready"
52  * state at the same time.  The controller task runs at the same priority as
53  * the continuous count task, and at a lower priority than the limited count
54  * task.
55  *
56  * One counter task loops indefinitely, incrementing the shared count variable
57  * on each iteration.  To ensure it has exclusive access to the variable it
58  * raises it's priority above that of the controller task before each
59  * increment, lowering it again to it's original priority before starting the
60  * next iteration.
61  *
62  * The other counter task increments the shared count variable on each
63  * iteration of it's loop until the count has reached a limit of 0xff - at
64  * which point it suspends itself.  It will not start a new loop until the
65  * controller task has made it "ready" again by calling vTaskResume (). 
66  * This second counter task operates at a higher priority than controller
67  * task so does not need to worry about mutual exclusion of the counter
68  * variable.
69  *
70  * The controller task is in two sections.  The first section controls and
71  * monitors the continuous count task.  When this section is operational the
72  * limited count task is suspended.  Likewise, the second section controls
73  * and monitors the limited count task.  When this section is operational the
74  * continuous count task is suspended.
75  *
76  * In the first section the controller task first takes a copy of the shared
77  * count variable.  To ensure mutual exclusion on the count variable it
78  * suspends the continuous count task, resuming it again when the copy has been
79  * taken.  The controller task then sleeps for a fixed period - during which
80  * the continuous count task will execute and increment the shared variable.
81  * When the controller task wakes it checks that the continuous count task
82  * has executed by comparing the copy of the shared variable with its current
83  * value.  This time, to ensure mutual exclusion, the scheduler itself is
84  * suspended with a call to vTaskSuspendAll ().  This is for demonstration
85  * purposes only and is not a recommended technique due to its inefficiency.
86  *
87  * After a fixed number of iterations the controller task suspends the
88  * continuous count task, and moves on to its second section.
89  *
90  * At the start of the second section the shared variable is cleared to zero.
91  * The limited count task is then woken from it's suspension by a call to
92  * vTaskResume ().  As this counter task operates at a higher priority than
93  * the controller task the controller task should not run again until the
94  * shared variable has been counted up to the limited value causing the counter
95  * task to suspend itself.  The next line after vTaskResume () is therefore
96  * a check on the shared variable to ensure everything is as expected.
97  *
98  *
99  * The second test consists of a couple of very simple tasks that post onto a
100  * queue while the scheduler is suspended.  This test was added to test parts
101  * of the scheduler not exercised by the first test.
102  *
103  *
104  * The final set of two tasks implements a third test.  This simply raises the
105  * priority of a task while the scheduler is suspended.  Again this test was
106  * added to exercise parts of the code not covered by the first test.
107  *
108  * \page Priorities dynamic.c
109  * \ingroup DemoFiles
110  * <HR>
111  */
112
113 /*
114 Changes from V2.0.0
115
116         + Delay periods are now specified using variables and constants of
117           portTickType rather than unsigned portLONG.
118         + Added a second, simple test that uses the functions
119           vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask().
120
121 Changes from V3.1.1
122
123         + Added a third simple test that uses the vTaskPrioritySet() function
124           while the scheduler is suspended.
125         + Modified the controller task slightly to test the calling of
126           vTaskResumeAll() while the scheduler is suspended.
127 */
128
129 #include <stdlib.h>
130
131 /* Scheduler include files. */
132 #include "FreeRTOS.h"
133 #include "task.h"
134 #include "semphr.h"
135
136 /* Demo app include files. */
137 #include "dynamic.h"
138 #include "print.h"
139
140 /* Function that implements the "limited count" task as described above. */
141 static void vLimitedIncrementTask( void * pvParameters );
142
143 /* Function that implements the "continuous count" task as described above. */
144 static void vContinuousIncrementTask( void * pvParameters );
145
146 /* Function that implements the controller task as described above. */
147 static void vCounterControlTask( void * pvParameters );
148
149 /* The simple test functions that check sending and receiving while the
150 scheduler is suspended. */
151 static void vQueueReceiveWhenSuspendedTask( void *pvParameters );
152 static void vQueueSendWhenSuspendedTask( void *pvParameters );
153
154 /* The simple test functions that check raising and lowering of task priorities
155 while the scheduler is suspended. */
156 static void prvChangePriorityWhenSuspendedTask( void *pvParameters );
157 static void prvChangePriorityHelperTask( void *pvParameters );
158
159
160 /* Demo task specific constants. */
161 #define priSTACK_SIZE                           ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE )
162 #define priSLEEP_TIME                           ( ( portTickType ) 50 )
163 #define priLOOPS                                        ( 5 )
164 #define priMAX_COUNT                            ( ( unsigned portLONG ) 0xff )
165 #define priNO_BLOCK                                     ( ( portTickType ) 0 )
166 #define priSUSPENDED_QUEUE_LENGTH       ( 1 )
167
168 /*-----------------------------------------------------------*/
169
170 /* Handles to the two counter tasks.  These could be passed in as parameters
171 to the controller task to prevent them having to be file scope. */
172 static xTaskHandle xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle;
173
174 /* The shared counter variable.  This is passed in as a parameter to the two
175 counter variables for demonstration purposes. */
176 static unsigned portLONG ulCounter;
177
178 /* Variable used in a similar way by the test that checks the raising and
179 lowering of task priorities while the scheduler is suspended. */
180 static unsigned portLONG ulPrioritySetCounter;
181
182 /* Variables used to check that the tasks are still operating without error.
183 Each complete iteration of the controller task increments this variable
184 provided no errors have been found.  The variable maintaining the same value
185 is therefore indication of an error. */
186 static unsigned portSHORT usCheckVariable = ( unsigned portSHORT ) 0;
187 static portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
188 static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
189 static portBASE_TYPE xPriorityRaiseWhenSuspendedError = pdFALSE;
190
191 /* Queue used by the second test. */
192 xQueueHandle xSuspendedTestQueue;
193
194 /*-----------------------------------------------------------*/
195 /*
196  * Start the seven tasks as described at the top of the file.
197  * Note that the limited count task is given a higher priority.
198  */
199 void vStartDynamicPriorityTasks( void )
200 {
201         xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned portLONG ) );
202         xTaskCreate( vContinuousIncrementTask, "CONT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
203         xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
204         xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
205         xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
206         xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
207         xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
208         xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle );
209 }
210 /*-----------------------------------------------------------*/
211
212 /*
213  * Just loops around incrementing the shared variable until the limit has been
214  * reached.  Once the limit has been reached it suspends itself.
215  */
216 static void vLimitedIncrementTask( void * pvParameters )
217 {
218 unsigned portLONG *pulCounter;
219
220         /* Take a pointer to the shared variable from the parameters passed into
221         the task. */
222         pulCounter = ( unsigned portLONG * ) pvParameters;
223
224         /* This will run before the control task, so the first thing it does is
225         suspend - the control task will resume it when ready. */
226         vTaskSuspend( NULL );
227
228         for( ;; )
229         {
230                 /* Just count up to a value then suspend. */
231                 ( *pulCounter )++;     
232                
233                 if( *pulCounter >= priMAX_COUNT )
234                 {
235                         vTaskSuspend( NULL );
236                 }       
237         }
238 }
239 /*-----------------------------------------------------------*/
240
241 /*
242  * Just keep counting the shared variable up.  The control task will suspend
243  * this task when it wants.
244  */
245 static void vContinuousIncrementTask( void * pvParameters )
246 {
247 unsigned portLONG *pulCounter;
248 unsigned portBASE_TYPE uxOurPriority;
249
250         /* Take a pointer to the shared variable from the parameters passed into
251         the task. */
252         pulCounter = ( unsigned portLONG * ) pvParameters;
253
254         /* Query our priority so we can raise it when exclusive access to the
255         shared variable is required. */
256         uxOurPriority = uxTaskPriorityGet( NULL );
257
258         for( ;; )
259         {
260                 /* Raise our priority above the controller task to ensure a context
261                 switch does not occur while we are accessing this variable. */
262                 vTaskPrioritySet( NULL, uxOurPriority + 1 );
263                         ( *pulCounter )++;             
264                 vTaskPrioritySet( NULL, uxOurPriority );
265
266                 #if configUSE_PREEMPTION == 0
267                         taskYIELD();
268                 #endif
269         }
270 }
271 /*-----------------------------------------------------------*/
272
273 /*
274  * Controller task as described above.
275  */
276 static void vCounterControlTask( void * pvParameters )
277 {
278 unsigned portLONG ulLastCounter;
279 portSHORT sLoops;
280 portSHORT sError = pdFALSE;
281 const portCHAR * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n";
282 const portCHAR * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
283
284         /* Just to stop warning messages. */
285         ( void ) pvParameters;
286
287         /* Queue a message for printing to say the task has started. */
288         vPrintDisplayMessage( &pcTaskStartMsg );
289
290         for( ;; )
291         {
292                 /* Start with the counter at zero. */
293                 ulCounter = ( unsigned portLONG ) 0;
294
295                 /* First section : */
296
297                 /* Check the continuous count task is running. */
298                 for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
299                 {
300                         /* Suspend the continuous count task so we can take a mirror of the
301                         shared variable without risk of corruption. */
302                         vTaskSuspend( xContinuousIncrementHandle );
303                                 ulLastCounter = ulCounter;
304                         vTaskResume( xContinuousIncrementHandle );
305                        
306                         /* Now delay to ensure the other task has processor time. */
307                         vTaskDelay( priSLEEP_TIME );
308
309                         /* Check the shared variable again.  This time to ensure mutual
310                         exclusion the whole scheduler will be locked.  This is just for
311                         demo purposes! */
312                         vTaskSuspendAll();
313                         {
314                                 if( ulLastCounter == ulCounter )
315                                 {
316                                         /* The shared variable has not changed.  There is a problem
317                                         with the continuous count task so flag an error. */
318                                         sError = pdTRUE;
319                                         xTaskResumeAll();
320                                                 vPrintDisplayMessage( &pcTaskFailMsg );
321                                         vTaskSuspendAll();
322                                 }
323                         }
324                         xTaskResumeAll();
325                 }
326
327
328                 /* Second section: */
329
330                 /* Suspend the continuous counter task so it stops accessing the shared variable. */
331                 vTaskSuspend( xContinuousIncrementHandle );
332
333                 /* Reset the variable. */
334                 ulCounter = ( unsigned portLONG ) 0;
335
336                 /* Resume the limited count task which has a higher priority than us.
337                 We should therefore not return from this call until the limited count
338                 task has suspended itself with a known value in the counter variable.
339                 The scheduler suspension is not necessary but is included for test
340                 purposes. */
341                 vTaskSuspendAll();
342                         vTaskResume( xLimitedIncrementHandle );
343                 xTaskResumeAll();
344
345                 /* Does the counter variable have the expected value? */
346                 if( ulCounter != priMAX_COUNT )
347                 {
348                         sError = pdTRUE;
349                         vPrintDisplayMessage( &pcTaskFailMsg );
350                 }
351
352                 if( sError == pdFALSE )
353                 {
354                         /* If no errors have occurred then increment the check variable. */
355                         portENTER_CRITICAL();
356                                 usCheckVariable++;
357                         portEXIT_CRITICAL();
358                 }
359
360                 #if configUSE_PREEMPTION == 0
361                         taskYIELD();
362                 #endif
363
364                 /* Resume the continuous count task and do it all again. */
365                 vTaskResume( xContinuousIncrementHandle );
366         }
367 }
368 /*-----------------------------------------------------------*/
369
370 static void vQueueSendWhenSuspendedTask( void *pvParameters )
371 {
372 static unsigned portLONG ulValueToSend = ( unsigned portLONG ) 0;
373 const portCHAR * const pcTaskStartMsg = "Queue send while suspended task started.\r\n";
374 const portCHAR * const pcTaskFailMsg = "Queue send while suspended failed.\r\n";
375
376         /* Just to stop warning messages. */
377         ( void ) pvParameters;
378
379         /* Queue a message for printing to say the task has started. */
380         vPrintDisplayMessage( &pcTaskStartMsg );
381
382         for( ;; )
383         {
384                 vTaskSuspendAll();
385                 {
386                         /* We must not block while the scheduler is suspended! */
387                         if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
388                         {
389                                 if( xSuspendedQueueSendError == pdFALSE )
390                                 {
391                                         xTaskResumeAll();
392                                                 vPrintDisplayMessage( &pcTaskFailMsg );
393                                         vTaskSuspendAll();
394                                 }
395
396                                 xSuspendedQueueSendError = pdTRUE;
397                         }
398                 }
399                 xTaskResumeAll();
400
401                 vTaskDelay( priSLEEP_TIME );
402
403                 ++ulValueToSend;
404         }
405 }
406 /*-----------------------------------------------------------*/
407
408 static void vQueueReceiveWhenSuspendedTask( void *pvParameters )
409 {
410 static unsigned portLONG ulExpectedValue = ( unsigned portLONG ) 0, ulReceivedValue;
411 const portCHAR * const pcTaskStartMsg = "Queue receive while suspended task started.\r\n";
412 const portCHAR * const pcTaskFailMsg = "Queue receive while suspended failed.\r\n";
413 portBASE_TYPE xGotValue;
414
415         /* Just to stop warning messages. */
416         ( void ) pvParameters;
417
418         /* Queue a message for printing to say the task has started. */
419         vPrintDisplayMessage( &pcTaskStartMsg );
420
421         for( ;; )
422         {
423                 do
424                 {
425                         /* Suspending the scheduler here is fairly pointless and
426                         undesirable for a normal application.  It is done here purely
427                         to test the scheduler.  The inner xTaskResumeAll() should
428                         never return pdTRUE as the scheduler is still locked by the
429                         outer call. */
430                         vTaskSuspendAll();
431                         {
432                                 vTaskSuspendAll();
433                                 {
434                                         xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
435                                 }
436                                 if( xTaskResumeAll() )
437                                 {
438                                         xSuspendedQueueReceiveError = pdTRUE;
439                                 }
440                         }
441                         xTaskResumeAll();
442
443                         #if configUSE_PREEMPTION == 0
444                                 taskYIELD();
445                         #endif
446
447                 } while( xGotValue == pdFALSE );
448
449                 if( ulReceivedValue != ulExpectedValue )
450                 {
451                         if( xSuspendedQueueReceiveError == pdFALSE )
452                         {
453                                 vPrintDisplayMessage( &pcTaskFailMsg );
454                         }
455                         xSuspendedQueueReceiveError = pdTRUE;
456                 }
457
458                 ++ulExpectedValue;
459         }
460 }
461 /*-----------------------------------------------------------*/
462
463 static void prvChangePriorityWhenSuspendedTask( void *pvParameters )
464 {
465 const portCHAR * const pcTaskStartMsg = "Priority change when suspended task started.\r\n";
466 const portCHAR * const pcTaskFailMsg = "Priority change when suspended task failed.\r\n";
467
468         /* Just to stop warning messages. */
469         ( void ) pvParameters;
470
471         /* Queue a message for printing to say the task has started. */
472         vPrintDisplayMessage( &pcTaskStartMsg );       
473        
474         for( ;; )
475         {
476                 /* Start with the counter at 0 so we know what the counter should be
477                 when we check it next. */
478                 ulPrioritySetCounter = ( unsigned portLONG ) 0;
479
480                 /* Resume the helper task.  At this time it has a priority lower than
481                 ours so no context switch should occur. */
482                 vTaskResume( xChangePriorityWhenSuspendedHandle );
483
484                 /* Check to ensure the task just resumed has not executed. */
485                 portENTER_CRITICAL();
486                 {
487                         if( ulPrioritySetCounter != ( unsigned portLONG ) 0 )
488                         {
489                                 xPriorityRaiseWhenSuspendedError = pdTRUE;
490                                 vPrintDisplayMessage( &pcTaskFailMsg );
491                         }
492                 }
493                 portEXIT_CRITICAL();
494
495                 /* Now try raising the priority while the scheduler is suspended. */
496                 vTaskSuspendAll();
497                 {
498                         vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) );
499
500                         /* Again, even though the helper task has a priority greater than
501                         ours, it should not have executed yet because the scheduler is
502                         suspended. */
503                         portENTER_CRITICAL();
504                         {
505                                 if( ulPrioritySetCounter != ( unsigned portLONG ) 0 )
506                                 {
507                                         xPriorityRaiseWhenSuspendedError = pdTRUE;
508                                         vPrintDisplayMessage( &pcTaskFailMsg );
509                                 }
510                         }
511                         portEXIT_CRITICAL();
512                 }
513                 xTaskResumeAll();
514                
515                 /* Now the scheduler has been resumed the helper task should
516                 immediately preempt us and execute.  When it executes it will increment
517                 the ulPrioritySetCounter exactly once before suspending itself.
518
519                 We should now always find the counter set to 1. */
520                 portENTER_CRITICAL();
521                 {
522                         if( ulPrioritySetCounter != ( unsigned portLONG ) 1 )
523                         {
524                                 xPriorityRaiseWhenSuspendedError = pdTRUE;
525                                 vPrintDisplayMessage( &pcTaskFailMsg );
526                         }
527                 }
528                 portEXIT_CRITICAL();
529
530                 /* Delay until we try this again. */           
531                 vTaskDelay( priSLEEP_TIME * 2 );
532                
533                 /* Set the priority of the helper task back ready for the next
534                 execution of this task. */
535                 vTaskSuspendAll();
536                         vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY );                               
537                 xTaskResumeAll();                               
538         }
539 }
540 /*-----------------------------------------------------------*/
541
542 static void prvChangePriorityHelperTask( void *pvParameters )
543 {
544         /* Just to stop warning messages. */
545         ( void ) pvParameters;
546
547         for( ;; )
548         {
549                 /* This is the helper task for prvChangePriorityWhenSuspendedTask().
550                 It has it's priority raised and lowered.  When it runs it simply
551                 increments the counter then suspends itself again.  This allows
552                 prvChangePriorityWhenSuspendedTask() to know how many times it has
553                 executed. */
554                 ulPrioritySetCounter++;
555                 vTaskSuspend( NULL );
556         }
557 }
558 /*-----------------------------------------------------------*/
559
560 /* Called to check that all the created tasks are still running without error. */
561 portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
562 {
563 /* Keep a history of the check variables so we know if it has been incremented
564 since the last call. */
565 static unsigned portSHORT usLastTaskCheck = ( unsigned portSHORT ) 0;
566 portBASE_TYPE xReturn = pdTRUE;
567
568         /* Check the tasks are still running by ensuring the check variable
569         is still incrementing. */
570
571         if( usCheckVariable == usLastTaskCheck )
572         {
573                 /* The check has not incremented so an error exists. */
574                 xReturn = pdFALSE;
575         }
576
577         if( xSuspendedQueueSendError == pdTRUE )
578         {
579                 xReturn = pdFALSE;
580         }
581
582         if( xSuspendedQueueReceiveError == pdTRUE )
583         {
584                 xReturn = pdFALSE;
585         }
586
587         if( xPriorityRaiseWhenSuspendedError == pdTRUE )
588         {
589                 xReturn = pdFALSE;
590         }
591
592         usLastTaskCheck = usCheckVariable;
593         return xReturn;
594 }
595
596
597
598
Note: See TracBrowser for help on using the browser.