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

Revision 14, 15.4 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 exercises the event mechanism whereby more than one task is
50  * blocked waiting for the same event.
51  *
52  * The demo creates five tasks - four 'event' tasks, and a controlling task.
53  * The event tasks have various different priorities and all block on reading
54  * the same queue.  The controlling task writes data to the queue, then checks
55  * to see which of the event tasks read the data from the queue.  The
56  * controlling task has the lowest priority of all the tasks so is guaranteed
57  * to always get preempted immediately upon writing to the queue.
58  *
59  * By selectively suspending and resuming the event tasks the controlling task
60  * can check that the highest priority task that is blocked on the queue is the
61  * task that reads the posted data from the queue.
62  *
63  * Two of the event tasks share the same priority.  When neither of these tasks
64  * are suspended they should alternate - one reading one message from the queue,
65  * the other the next message, etc.
66  */
67
68 /* Standard includes. */
69 #include <stdlib.h>
70 #include <stdio.h>
71 #include <string.h>
72
73 /* Scheduler include files. */
74 #include "FreeRTOS.h"
75 #include "task.h"
76 #include "queue.h"
77
78 /* Demo program include files. */
79 #include "mevents.h"
80 #include "print.h"
81
82 /* Demo specific constants. */
83 #define evtSTACK_SIZE           ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
84 #define evtNUM_TASKS            ( 4 )
85 #define evtQUEUE_LENGTH         ( ( unsigned portBASE_TYPE ) 3 )
86 #define evtNO_DELAY                                             0
87
88 /* Just indexes used to uniquely identify the tasks.  Note that two tasks are
89 'highest' priority. */
90 #define evtHIGHEST_PRIORITY_INDEX_2             3
91 #define evtHIGHEST_PRIORITY_INDEX_1             2
92 #define evtMEDIUM_PRIORITY_INDEX                1
93 #define evtLOWEST_PRIORITY_INDEX                0
94
95 /* Each event task increments one of these counters each time it reads data
96 from the queue. */
97 static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
98
99 /* Each time the controlling task posts onto the queue it increments the
100 expected count of the task that it expected to read the data from the queue
101 (i.e. the task with the highest priority that should be blocked on the queue). 
102
103 xExpectedTaskCounters are incremented from the controlling task, and
104 xTaskCounters are incremented from the individual event tasks - therefore
105 comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
106 correct task was unblocked by the post. */
107 static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
108
109 /* Handles to the four event tasks.  These are required to suspend and resume
110 the tasks. */
111 static xTaskHandle xCreatedTasks[ evtNUM_TASKS ];
112
113 /* The single queue onto which the controlling task posts, and the four event
114 tasks block. */
115 static xQueueHandle xQueue;
116
117 /* Flag used to indicate whether or not an error has occurred at any time.
118 An error is either the queue being full when not expected, or an unexpected
119 task reading data from the queue. */
120 static portBASE_TYPE xHealthStatus = pdPASS;
121
122 /*-----------------------------------------------------------*/
123
124 /* Function that implements the event task.  This is created four times. */
125 static void prvMultiEventTask( void *pvParameters );
126
127 /* Function that implements the controlling task. */
128 static void prvEventControllerTask( void *pvParameters );
129
130 /* This is a utility function that posts data to the queue, then compares
131 xExpectedTaskCounters with xTaskCounters to ensure everything worked as
132 expected.
133
134 The event tasks all have higher priorities the controlling task.  Therefore
135 the controlling task will always get preempted between writhing to the queue
136 and checking the task counters.
137
138 @param xExpectedTask  The index to the task that the controlling task thinks
139                       should be the highest priority task waiting for data, and
140                                           therefore the task that will unblock.
141                                          
142 @param  xIncrement    The number of items that should be written to the queue.
143 */
144 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );
145
146 /* This is just incremented each cycle of the controlling tasks function so
147 the main application can ensure the test is still running. */
148 static portBASE_TYPE xCheckVariable = 0;
149
150 /*-----------------------------------------------------------*/
151
152 void vStartMultiEventTasks( void )
153 {
154         /* Create the queue to be used for all the communications. */
155         xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
156
157         /* Start the controlling task.  This has the idle priority to ensure it is
158         always preempted by the event tasks. */
159         xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
160
161         /* Start the four event tasks.  Note that two have priority 3, one
162         priority 2 and the other priority 1. */
163         xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
164         xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
165         xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
166         xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
167 }
168 /*-----------------------------------------------------------*/
169
170 static void prvMultiEventTask( void *pvParameters )
171 {
172 portBASE_TYPE *pxCounter;
173 unsigned portBASE_TYPE uxDummy;
174 const portCHAR * const pcTaskStartMsg = "Multi event task started.\r\n";
175
176         /* The variable this task will increment is passed in as a parameter. */
177         pxCounter = ( portBASE_TYPE * ) pvParameters;
178
179         vPrintDisplayMessage( &pcTaskStartMsg );
180
181         for( ;; )
182         {
183                 /* Block on the queue. */
184                 if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
185                 {
186                         /* We unblocked by reading the queue - so simply increment
187                         the counter specific to this task instance. */
188                         ( *pxCounter )++;
189                 }
190                 else
191                 {
192                         xHealthStatus = pdFAIL;
193                 }
194         }
195 }
196 /*-----------------------------------------------------------*/
197
198 static void prvEventControllerTask( void *pvParameters )
199 {
200 const portCHAR * const pcTaskStartMsg = "Multi event controller task started.\r\n";
201 portBASE_TYPE xDummy = 0;
202
203         /* Just to stop warnings. */
204         ( void ) pvParameters;
205
206         vPrintDisplayMessage( &pcTaskStartMsg );
207
208         for( ;; )
209         {
210                 /* All tasks are blocked on the queue.  When a message is posted one of
211                 the two tasks that share the highest priority should unblock to read
212                 the queue.  The next message written should unblock the other task with
213                 the same high priority, and so on in order.   No other task should
214                 unblock to read data as they have lower priorities. */
215
216                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
217                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
218                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
219                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
220                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
221
222                 /* For the rest of these tests we don't need the second 'highest'
223                 priority task - so it is suspended. */
224                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
225
226
227
228                 /* Now suspend the other highest priority task.  The medium priority
229                 task will then be the task with the highest priority that remains
230                 blocked on the queue. */
231                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
232                
233                 /* This time, when we post onto the queue we will expect the medium
234                 priority task to unblock and preempt us. */
235                 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
236
237                 /* Now try resuming the highest priority task while the scheduler is
238                 suspended.  The task should start executing as soon as the scheduler
239                 is resumed - therefore when we post to the queue again, the highest
240                 priority task should again preempt us. */
241                 vTaskSuspendAll();
242                         vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
243                 xTaskResumeAll();
244                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
245                
246                 /* Now we are going to suspend the high and medium priority tasks.  The
247                 low priority task should then preempt us.  Again the task suspension is
248                 done with the whole scheduler suspended just for test purposes. */
249                 vTaskSuspendAll();
250                         vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
251                         vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
252                 xTaskResumeAll();
253                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
254                
255                 /* Do the same basic test another few times - selectively suspending
256                 and resuming tasks and each time calling prvCheckTaskCounters() passing
257                 to the function the number of the task we expected to be unblocked by
258                 the     post. */
259
260                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
261                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
262                
263                 vTaskSuspendAll(); /* Just for test. */
264                         vTaskSuspendAll(); /* Just for test. */
265                                 vTaskSuspendAll(); /* Just for even more test. */
266                                         vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
267                                 xTaskResumeAll();
268                         xTaskResumeAll();
269                 xTaskResumeAll();
270                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
271                
272                 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
273                 prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
274                
275                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
276                 prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
277
278                 /* Now a slight change, first suspend all tasks. */
279                 vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
280                 vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
281                 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
282                
283                 /* Now when we resume the low priority task and write to the queue 3
284                 times.  We expect the low priority task to service the queue three
285                 times. */
286                 vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
287                 prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
288                
289                 /* Again suspend all tasks (only the low priority task is not suspended
290                 already). */
291                 vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
292                
293                 /* This time we are going to suspend the scheduler, resume the low
294                 priority task, then resume the high priority task.  In this state we
295                 will write to the queue three times.  When the scheduler is resumed
296                 we expect the high priority task to service all three messages. */
297                 vTaskSuspendAll();
298                 {
299                         vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
300                         vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
301                        
302                         for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
303                         {
304                                 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
305                                 {
306                                         xHealthStatus = pdFAIL;
307                                 }
308                         }                       
309                        
310                         /* The queue should not have been serviced yet!.  The scheduler
311                         is still suspended. */
312                         if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
313                         {
314                                 xHealthStatus = pdFAIL;
315                         }
316                 }
317                 xTaskResumeAll();
318
319                 /* We should have been preempted by resuming the scheduler - so by the
320                 time we are running again we expect the high priority task to have
321                 removed three items from the queue. */
322                 xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
323                 if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
324                 {
325                         xHealthStatus = pdFAIL;
326                 }
327                
328                 /* The medium priority and second high priority tasks are still
329                 suspended.  Make sure to resume them before starting again. */
330                 vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
331                 vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
332
333                 /* Just keep incrementing to show the task is still executing. */
334                 xCheckVariable++;
335         }
336 }
337 /*-----------------------------------------------------------*/
338
339 static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )
340 {
341 portBASE_TYPE xDummy = 0;
342
343         /* Write to the queue the requested number of times.  The data written is
344         not important. */
345         for( xDummy = 0; xDummy < xIncrement; xDummy++ )
346         {
347                 if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
348                 {
349                         /* Did not expect to ever find the queue full. */
350                         xHealthStatus = pdFAIL;
351                 }
352         }
353
354         /* All the tasks blocked on the queue have a priority higher than the
355         controlling task.  Writing to the queue will therefore have caused this
356         task to be preempted.  By the time this line executes the event task will
357         have executed and incremented its counter.  Increment the expected counter
358         to the same value. */
359         ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
360
361         /* Check the actual counts and expected counts really are the same. */
362         if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
363         {
364                 /* The counters were not the same.  This means a task we did not expect
365                 to unblock actually did unblock. */
366                 xHealthStatus = pdFAIL;
367         }
368 }
369 /*-----------------------------------------------------------*/
370
371 portBASE_TYPE xAreMultiEventTasksStillRunning( void )
372 {
373 static portBASE_TYPE xPreviousCheckVariable = 0;
374
375         /* Called externally to periodically check that this test is still
376         operational. */
377
378         if( xPreviousCheckVariable == xCheckVariable )
379         {
380                 xHealthStatus = pdFAIL;
381         }
382        
383         xPreviousCheckVariable = xCheckVariable;
384        
385         return xHealthStatus;   
386 }
387
388
Note: See TracBrowser for help on using the browser.