root/webserver/example/freeRTOSexample/Demo/Common/Minimal/AltQTest.c

Revision 14, 17.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 /*
50  * This file implements the same demo and test as GenQTest.c, but uses the
51  * light weight API in place of the fully featured API.
52  *
53  * See the comments at the top of GenQTest.c for a description.
54  */
55
56
57 #include <stdlib.h>
58
59 /* Scheduler include files. */
60 #include "FreeRTOS.h"
61 #include "task.h"
62 #include "queue.h"
63 #include "semphr.h"
64
65 /* Demo program include files. */
66 #include "AltQTest.h"
67
68 #define genqQUEUE_LENGTH                ( 5 )
69 #define genqNO_BLOCK                    ( 0 )
70
71 #define genqMUTEX_LOW_PRIORITY          ( tskIDLE_PRIORITY )
72 #define genqMUTEX_TEST_PRIORITY         ( tskIDLE_PRIORITY + 1 )
73 #define genqMUTEX_MEDIUM_PRIORITY       ( tskIDLE_PRIORITY + 2 )
74 #define genqMUTEX_HIGH_PRIORITY         ( tskIDLE_PRIORITY + 3 )
75
76 /*-----------------------------------------------------------*/
77
78 /*
79  * Tests the behaviour of the xQueueAltSendToFront() and xQueueAltSendToBack()
80  * macros by using both to fill a queue, then reading from the queue to
81  * check the resultant queue order is as expected.  Queue data is also
82  * peeked.
83  */
84 static void prvSendFrontAndBackTest( void *pvParameters );
85
86 /*
87  * The following three tasks are used to demonstrate the mutex behaviour.
88  * Each task is given a different priority to demonstrate the priority
89  * inheritance mechanism.
90  *
91  * The low priority task obtains a mutex.  After this a high priority task
92  * attempts to obtain the same mutex, causing its priority to be inherited
93  * by the low priority task.  The task with the inherited high priority then
94  * resumes a medium priority task to ensure it is not blocked by the medium
95  * priority task while it holds the inherited high priority.  Once the mutex
96  * is returned the task with the inherited priority returns to its original
97  * low priority, and is therefore immediately preempted by first the high
98  * priority task and then the medium prioroity task before it can continue.
99  */
100 static void prvLowPriorityMutexTask( void *pvParameters );
101 static void prvMediumPriorityMutexTask( void *pvParameters );
102 static void prvHighPriorityMutexTask( void *pvParameters );
103
104 /*-----------------------------------------------------------*/
105
106 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
107 detected in any of the tasks. */
108 static portBASE_TYPE xErrorDetected = pdFALSE;
109
110 /* Counters that are incremented on each cycle of a test.  This is used to
111 detect a stalled task - a test that is no longer running. */
112 static volatile unsigned portLONG ulLoopCounter = 0;
113 static volatile unsigned portLONG ulLoopCounter2 = 0;
114
115 /* The variable that is guarded by the mutex in the mutex demo tasks. */
116 static volatile unsigned portLONG ulGuardedVariable = 0;
117
118 /* Handles used in the mutext test to suspend and resume the high and medium
119 priority mutex test tasks. */
120 static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
121
122 /*-----------------------------------------------------------*/
123
124 void vStartAltGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
125 {
126 xQueueHandle xQueue;
127 xSemaphoreHandle xMutex;
128
129         /* Create the queue that we are going to use for the
130         prvSendFrontAndBackTest demo. */
131         xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
132
133         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
134         in use.  The queue registry is provided as a means for kernel aware
135         debuggers to locate queues and has no purpose if a kernel aware debugger
136         is not being used.  The call to vQueueAddToRegistry() will be removed
137         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
138         defined to be less than 1. */
139         vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Alt_Gen_Test_Queue" );
140
141         /* Create the demo task and pass it the queue just created.  We are
142         passing the queue handle by value so it does not matter that it is
143         declared on the stack here. */
144         xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * ) "FGenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
145
146         /* Create the mutex used by the prvMutexTest task. */
147         xMutex = xSemaphoreCreateMutex();
148
149         /* vQueueAddToRegistry() adds the mutex to the registry, if one is
150         in use.  The registry is provided as a means for kernel aware
151         debuggers to locate mutex and has no purpose if a kernel aware debugger
152         is not being used.  The call to vQueueAddToRegistry() will be removed
153         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
154         defined to be less than 1. */
155         vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Alt_Q_Mutex" );
156
157         /* Create the mutex demo tasks and pass it the mutex just created.  We are
158         passing the mutex handle by value so it does not matter that it is declared
159         on the stack here. */
160         xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * ) "FMuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
161         xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * ) "FMuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
162         xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * ) "FMuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
163 }
164 /*-----------------------------------------------------------*/
165
166 static void prvSendFrontAndBackTest( void *pvParameters )
167 {
168 unsigned portLONG ulData, ulData2;
169 xQueueHandle xQueue;
170
171         #ifdef USE_STDIO
172         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
173        
174                 const portCHAR * const pcTaskStartMsg = "Alt queue SendToFront/SendToBack/Peek test started.\r\n";
175
176                 /* Queue a message for printing to say the task has started. */
177                 vPrintDisplayMessage( &pcTaskStartMsg );
178         #endif
179
180         xQueue = ( xQueueHandle ) pvParameters;
181
182         for( ;; )
183         {
184                 /* The queue is empty, so sending an item to the back of the queue
185                 should have the same efect as sending it to the front of the queue.
186
187                 First send to the front and check everything is as expected. */
188                 xQueueAltSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
189
190                 if( uxQueueMessagesWaiting( xQueue ) != 1 )
191                 {
192                         xErrorDetected = pdTRUE;
193                 }
194
195                 if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
196                 {
197                         xErrorDetected = pdTRUE;
198                 }
199
200                 /* The data we sent to the queue should equal the data we just received
201                 from the queue. */
202                 if( ulLoopCounter != ulData )
203                 {
204                         xErrorDetected = pdTRUE;
205                 }
206
207                 /* Then do the same, sending the data to the back, checking everything
208                 is as expected. */
209                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
210                 {
211                         xErrorDetected = pdTRUE;
212                 }
213
214                 xQueueAltSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
215
216                 if( uxQueueMessagesWaiting( xQueue ) != 1 )
217                 {
218                         xErrorDetected = pdTRUE;
219                 }
220
221                 if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
222                 {
223                         xErrorDetected = pdTRUE;
224                 }
225
226                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
227                 {
228                         xErrorDetected = pdTRUE;
229                 }
230
231                 /* The data we sent to the queue should equal the data we just received
232                 from the queue. */
233                 if( ulLoopCounter != ulData )
234                 {
235                         xErrorDetected = pdTRUE;
236                 }
237
238                 #if configUSE_PREEMPTION == 0
239                         taskYIELD();
240                 #endif
241
242
243
244                 /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
245                 for( ulData = 2; ulData < 5; ulData++ )
246                 {
247                         xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
248                 }
249
250                 /* Now the order in the queue should be 2, 3, 4, with 2 being the first
251                 thing to be read out.  Now add 1 then 0 to the front of the queue. */
252                 if( uxQueueMessagesWaiting( xQueue ) != 3 )
253                 {
254                         xErrorDetected = pdTRUE;
255                 }
256                 ulData = 1;
257                 xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
258                 ulData = 0;
259                 xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
260
261                 /* Now the queue should be full, and when we read the data out we
262                 should receive 0, 1, 2, 3, 4. */
263                 if( uxQueueMessagesWaiting( xQueue ) != 5 )
264                 {
265                         xErrorDetected = pdTRUE;
266                 }
267
268                 if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
269                 {
270                         xErrorDetected = pdTRUE;
271                 }
272
273                 if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
274                 {
275                         xErrorDetected = pdTRUE;
276                 }
277
278                 #if configUSE_PREEMPTION == 0
279                         taskYIELD();
280                 #endif
281
282                 /* Check the data we read out is in the expected order. */
283                 for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
284                 {
285                         /* Try peeking the data first. */
286                         if( xQueueAltPeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
287                         {
288                                 xErrorDetected = pdTRUE;
289                         }
290
291                         if( ulData != ulData2 )
292                         {
293                                 xErrorDetected = pdTRUE;
294                         }
295                        
296
297                         /* Now try receiving the data for real.  The value should be the
298                         same.  Clobber the value first so we know we really received it. */
299                         ulData2 = ~ulData2;
300                         if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
301                         {
302                                 xErrorDetected = pdTRUE;
303                         }
304
305                         if( ulData != ulData2 )
306                         {
307                                 xErrorDetected = pdTRUE;
308                         }
309                 }
310
311                 /* The queue should now be empty again. */
312                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
313                 {
314                         xErrorDetected = pdTRUE;
315                 }
316
317                 #if configUSE_PREEMPTION == 0
318                         taskYIELD();
319                 #endif
320
321
322                 /* Our queue is empty once more, add 10, 11 to the back. */
323                 ulData = 10;
324                 if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
325                 {
326                         xErrorDetected = pdTRUE;
327                 }
328                 ulData = 11;
329                 if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
330                 {
331                         xErrorDetected = pdTRUE;
332                 }
333
334                 if( uxQueueMessagesWaiting( xQueue ) != 2 )
335                 {
336                         xErrorDetected = pdTRUE;
337                 }
338
339                 /* Now we should have 10, 11 in the queue.  Add 7, 8, 9 to the
340                 front. */
341                 for( ulData = 9; ulData >= 7; ulData-- )
342                 {
343                         if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
344                         {
345                                 xErrorDetected = pdTRUE;
346                         }
347                 }
348
349                 /* Now check that the queue is full, and that receiving data provides
350                 the expected sequence of 7, 8, 9, 10, 11. */
351                 if( uxQueueMessagesWaiting( xQueue ) != 5 )
352                 {
353                         xErrorDetected = pdTRUE;
354                 }
355
356                 if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
357                 {
358                         xErrorDetected = pdTRUE;
359                 }
360
361                 if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
362                 {
363                         xErrorDetected = pdTRUE;
364                 }
365
366                 #if configUSE_PREEMPTION == 0
367                         taskYIELD();
368                 #endif
369
370                 /* Check the data we read out is in the expected order. */
371                 for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
372                 {
373                         if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
374                         {
375                                 xErrorDetected = pdTRUE;
376                         }
377
378                         if( ulData != ulData2 )
379                         {
380                                 xErrorDetected = pdTRUE;
381                         }
382                 }
383
384                 if( uxQueueMessagesWaiting( xQueue ) != 0 )
385                 {
386                         xErrorDetected = pdTRUE;
387                 }
388
389                 ulLoopCounter++;
390         }
391 }
392 /*-----------------------------------------------------------*/
393
394 static void prvLowPriorityMutexTask( void *pvParameters )
395 {
396 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
397
398         #ifdef USE_STDIO
399         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
400        
401                 const portCHAR * const pcTaskStartMsg = "Fast mutex with priority inheritance test started.\r\n";
402
403                 /* Queue a message for printing to say the task has started. */
404                 vPrintDisplayMessage( &pcTaskStartMsg );
405         #endif
406
407         ( void ) pvParameters;
408
409
410         for( ;; )
411         {
412                 /* Take the mutex.  It should be available now. */
413                 if( xSemaphoreAltTake( xMutex, genqNO_BLOCK ) != pdPASS )
414                 {
415                         xErrorDetected = pdTRUE;
416                 }
417
418                 /* Set our guarded variable to a known start value. */
419                 ulGuardedVariable = 0;
420
421                 /* Our priority should be as per that assigned when the task was
422                 created. */
423                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
424                 {
425                         xErrorDetected = pdTRUE;
426                 }
427
428                 /* Now unsuspend the high priority task.  This will attempt to take the
429                 mutex, and block when it finds it cannot obtain it. */
430                 vTaskResume( xHighPriorityMutexTask );
431
432                 /* We should now have inherited the prioritoy of the high priority task,
433                 as by now it will have attempted to get the mutex. */
434                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
435                 {
436                         xErrorDetected = pdTRUE;
437                 }
438
439                 /* We can attempt to set our priority to the test priority - between the
440                 idle priority and the medium/high test priorities, but our actual
441                 prioroity should remain at the high priority. */
442                 vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
443                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
444                 {
445                         xErrorDetected = pdTRUE;
446                 }
447
448                 /* Now unsuspend the medium priority task.  This should not run as our
449                 inherited priority is above that of the medium priority task. */
450                 vTaskResume( xMediumPriorityMutexTask );
451
452                 /* If the did run then it will have incremented our guarded variable. */
453                 if( ulGuardedVariable != 0 )
454                 {
455                         xErrorDetected = pdTRUE;
456                 }
457
458                 /* When we give back the semaphore our priority should be disinherited
459                 back to the priority to which we attempted to set ourselves.  This means
460                 that when the high priority task next blocks, the medium priority task
461                 should execute and increment the guarded variable.   When we next run
462                 both the high and medium priority tasks will have been suspended again. */
463                 if( xSemaphoreAltGive( xMutex ) != pdPASS )
464                 {
465                         xErrorDetected = pdTRUE;
466                 }
467
468                 /* Check that the guarded variable did indeed increment... */
469                 if( ulGuardedVariable != 1 )
470                 {
471                         xErrorDetected = pdTRUE;
472                 }
473
474                 /* ... and that our priority has been disinherited to
475                 genqMUTEX_TEST_PRIORITY. */
476                 if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
477                 {
478                         xErrorDetected = pdTRUE;
479                 }
480
481                 /* Set our priority back to our original priority ready for the next
482                 loop around this test. */
483                 vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
484
485                 /* Just to show we are still running. */
486                 ulLoopCounter2++;
487
488                 #if configUSE_PREEMPTION == 0
489                         taskYIELD();
490                 #endif         
491         }
492 }
493 /*-----------------------------------------------------------*/
494
495 static void prvMediumPriorityMutexTask( void *pvParameters )
496 {
497         ( void ) pvParameters;
498
499         for( ;; )
500         {
501                 /* The medium priority task starts by suspending itself.  The low
502                 priority task will unsuspend this task when required. */
503                 vTaskSuspend( NULL );
504
505                 /* When this task unsuspends all it does is increment the guarded
506                 variable, this is so the low priority task knows that it has
507                 executed. */
508                 ulGuardedVariable++;
509         }
510 }
511 /*-----------------------------------------------------------*/
512
513 static void prvHighPriorityMutexTask( void *pvParameters )
514 {
515 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
516
517         ( void ) pvParameters;
518
519         for( ;; )
520         {
521                 /* The high priority task starts by suspending itself.  The low
522                 priority task will unsuspend this task when required. */
523                 vTaskSuspend( NULL );
524
525                 /* When this task unsuspends all it does is attempt to obtain
526                 the mutex.  It should find the mutex is not available so a
527                 block time is specified. */
528                 if( xSemaphoreAltTake( xMutex, portMAX_DELAY ) != pdPASS )
529                 {
530                         xErrorDetected = pdTRUE;
531                 }
532
533                 /* When we eventually obtain the mutex we just give it back then
534                 return to suspend ready for the next test. */
535                 if( xSemaphoreAltGive( xMutex ) != pdPASS )
536                 {
537                         xErrorDetected = pdTRUE;
538                 }               
539         }
540 }
541 /*-----------------------------------------------------------*/
542
543 /* This is called to check that all the created tasks are still running. */
544 portBASE_TYPE xAreAltGenericQueueTasksStillRunning( void )
545 {
546 static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
547
548         /* If the demo task is still running then we expect the loopcounters to
549         have incremented since this function was last called. */
550         if( ulLastLoopCounter == ulLoopCounter )
551         {
552                 xErrorDetected = pdTRUE;
553         }
554
555         if( ulLastLoopCounter2 == ulLoopCounter2 )
556         {
557                 xErrorDetected = pdTRUE;
558         }
559
560         ulLastLoopCounter = ulLoopCounter;
561         ulLastLoopCounter2 = ulLoopCounter2;   
562
563         /* Errors detected in the task itself will have latched xErrorDetected
564         to true. */
565
566         return !xErrorDetected;
567 }
568
569
Note: See TracBrowser for help on using the browser.