FreeRTOS Real Time Operating System, Modified from Kenji Arai's initial port. See freertos.org for full documentation.

Fork of FreeRTOS_on_mbed_v1 by Kenji Arai

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GenQTest.c Source File

GenQTest.c

00001 /*
00002     FreeRTOS V6.0.3 - Copyright (C) 2010 Real Time Engineers Ltd.
00003 
00004     ***************************************************************************
00005     *                                                                         *
00006     * If you are:                                                             *
00007     *                                                                         *
00008     *    + New to FreeRTOS,                                                   *
00009     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
00010     *    + Looking for basic training,                                        *
00011     *    + Wanting to improve your FreeRTOS skills and productivity           *
00012     *                                                                         *
00013     * then take a look at the FreeRTOS eBook                                  *
00014     *                                                                         *
00015     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
00016     *                  http://www.FreeRTOS.org/Documentation                  *
00017     *                                                                         *
00018     * A pdf reference manual is also available.  Both are usually delivered   *
00019     * to your inbox within 20 minutes to two hours when purchased between 8am *
00020     * and 8pm GMT (although please allow up to 24 hours in case of            *
00021     * exceptional circumstances).  Thank you for your support!                *
00022     *                                                                         *
00023     ***************************************************************************
00024 
00025     This file is part of the FreeRTOS distribution.
00026 
00027     FreeRTOS is free software; you can redistribute it and/or modify it under
00028     the terms of the GNU General Public License (version 2) as published by the
00029     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
00030     ***NOTE*** The exception to the GPL is included to allow you to distribute
00031     a combined work that includes FreeRTOS without being obliged to provide the
00032     source code for proprietary components outside of the FreeRTOS kernel.
00033     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
00034     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00035     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00036     more details. You should have received a copy of the GNU General Public 
00037     License and the FreeRTOS license exception along with FreeRTOS; if not it 
00038     can be viewed here: http://www.freertos.org/a00114.html and also obtained 
00039     by writing to Richard Barry, contact details for whom are available on the
00040     FreeRTOS WEB site.
00041 
00042     1 tab == 4 spaces!
00043 
00044     http://www.FreeRTOS.org - Documentation, latest information, license and
00045     contact details.
00046 
00047     http://www.SafeRTOS.com - A version that is certified for use in safety
00048     critical systems.
00049 
00050     http://www.OpenRTOS.com - Commercial support, development, porting,
00051     licensing and training services.
00052 */
00053 
00054 
00055 /* 
00056  * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 - 
00057  * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and 
00058  * mutex behaviour. 
00059  *
00060  * See the comments above the prvSendFrontAndBackTest() and 
00061  * prvLowPriorityMutexTask() prototypes below for more information.
00062  */
00063 
00064 
00065 #include <stdlib.h>
00066 
00067 /* Scheduler include files. */
00068 #include "FreeRTOS.h"
00069 #include "task.h"
00070 #include "queue.h"
00071 #include "semphr.h"
00072 
00073 /* Demo program include files. */
00074 #include "GenQTest.h"
00075 
00076 #define genqQUEUE_LENGTH        ( 5 )
00077 #define genqNO_BLOCK            ( 0 )
00078 
00079 #define genqMUTEX_LOW_PRIORITY        ( tskIDLE_PRIORITY )
00080 #define genqMUTEX_TEST_PRIORITY        ( tskIDLE_PRIORITY + 1 )
00081 #define genqMUTEX_MEDIUM_PRIORITY    ( tskIDLE_PRIORITY + 2 )
00082 #define genqMUTEX_HIGH_PRIORITY        ( tskIDLE_PRIORITY + 3 )
00083 
00084 /*-----------------------------------------------------------*/
00085 
00086 /*
00087  * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
00088  * macros by using both to fill a queue, then reading from the queue to
00089  * check the resultant queue order is as expected.  Queue data is also
00090  * peeked.
00091  */
00092 static void prvSendFrontAndBackTest( void *pvParameters );
00093 
00094 /*
00095  * The following three tasks are used to demonstrate the mutex behaviour.
00096  * Each task is given a different priority to demonstrate the priority
00097  * inheritance mechanism.
00098  *
00099  * The low priority task obtains a mutex.  After this a high priority task
00100  * attempts to obtain the same mutex, causing its priority to be inherited
00101  * by the low priority task.  The task with the inherited high priority then
00102  * resumes a medium priority task to ensure it is not blocked by the medium
00103  * priority task while it holds the inherited high priority.  Once the mutex
00104  * is returned the task with the inherited priority returns to its original
00105  * low priority, and is therefore immediately preempted by first the high
00106  * priority task and then the medium prioroity task before it can continue.
00107  */
00108 static void prvLowPriorityMutexTask( void *pvParameters );
00109 static void prvMediumPriorityMutexTask( void *pvParameters );
00110 static void prvHighPriorityMutexTask( void *pvParameters );
00111 
00112 /*-----------------------------------------------------------*/
00113 
00114 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
00115 detected in any of the tasks. */
00116 static portBASE_TYPE xErrorDetected = pdFALSE;
00117 
00118 /* Counters that are incremented on each cycle of a test.  This is used to
00119 detect a stalled task - a test that is no longer running. */
00120 static volatile unsigned portLONG ulLoopCounter = 0;
00121 static volatile unsigned portLONG ulLoopCounter2 = 0;
00122 
00123 /* The variable that is guarded by the mutex in the mutex demo tasks. */
00124 static volatile unsigned portLONG ulGuardedVariable = 0;
00125 
00126 /* Handles used in the mutext test to suspend and resume the high and medium
00127 priority mutex test tasks. */
00128 static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
00129 
00130 /*-----------------------------------------------------------*/
00131 
00132 void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
00133 {
00134 xQueueHandle xQueue;
00135 xSemaphoreHandle xMutex;
00136 
00137     /* Create the queue that we are going to use for the
00138     prvSendFrontAndBackTest demo. */
00139     xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
00140 
00141     /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
00142     in use.  The queue registry is provided as a means for kernel aware 
00143     debuggers to locate queues and has no purpose if a kernel aware debugger
00144     is not being used.  The call to vQueueAddToRegistry() will be removed
00145     by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 
00146     defined to be less than 1. */
00147     vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );
00148 
00149     /* Create the demo task and pass it the queue just created.  We are
00150     passing the queue handle by value so it does not matter that it is
00151     declared on the stack here. */
00152     xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
00153 
00154     /* Create the mutex used by the prvMutexTest task. */
00155     xMutex = xSemaphoreCreateMutex();
00156 
00157     /* vQueueAddToRegistry() adds the mutex to the registry, if one is
00158     in use.  The registry is provided as a means for kernel aware 
00159     debuggers to locate mutexes and has no purpose if a kernel aware debugger
00160     is not being used.  The call to vQueueAddToRegistry() will be removed
00161     by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 
00162     defined to be less than 1. */
00163     vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );
00164 
00165     /* Create the mutex demo tasks and pass it the mutex just created.  We are
00166     passing the mutex handle by value so it does not matter that it is declared
00167     on the stack here. */
00168     xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
00169     xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
00170     xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
00171 }
00172 /*-----------------------------------------------------------*/
00173 
00174 static void prvSendFrontAndBackTest( void *pvParameters )
00175 {
00176 unsigned portLONG ulData, ulData2;
00177 xQueueHandle xQueue;
00178 
00179     #ifdef USE_STDIO
00180     void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
00181     
00182         const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
00183 
00184         /* Queue a message for printing to say the task has started. */
00185         vPrintDisplayMessage( &pcTaskStartMsg );
00186     #endif
00187 
00188     xQueue = ( xQueueHandle ) pvParameters;
00189 
00190     for( ;; )
00191     {
00192         /* The queue is empty, so sending an item to the back of the queue
00193         should have the same efect as sending it to the front of the queue.
00194 
00195         First send to the front and check everything is as expected. */
00196         xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
00197 
00198         if( uxQueueMessagesWaiting( xQueue ) != 1 )
00199         {
00200             xErrorDetected = pdTRUE;
00201         }
00202 
00203         if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
00204         {
00205             xErrorDetected = pdTRUE;
00206         }
00207 
00208         /* The data we sent to the queue should equal the data we just received
00209         from the queue. */
00210         if( ulLoopCounter != ulData )
00211         {
00212             xErrorDetected = pdTRUE;
00213         }
00214 
00215         /* Then do the same, sending the data to the back, checking everything
00216         is as expected. */
00217         if( uxQueueMessagesWaiting( xQueue ) != 0 )
00218         {
00219             xErrorDetected = pdTRUE;
00220         }
00221 
00222         xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
00223 
00224         if( uxQueueMessagesWaiting( xQueue ) != 1 )
00225         {
00226             xErrorDetected = pdTRUE;
00227         }
00228 
00229         if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
00230         {
00231             xErrorDetected = pdTRUE;
00232         }
00233 
00234         if( uxQueueMessagesWaiting( xQueue ) != 0 )
00235         {
00236             xErrorDetected = pdTRUE;
00237         }
00238 
00239         /* The data we sent to the queue should equal the data we just received
00240         from the queue. */
00241         if( ulLoopCounter != ulData )
00242         {
00243             xErrorDetected = pdTRUE;
00244         }
00245 
00246         #if configUSE_PREEMPTION == 0
00247             taskYIELD();
00248         #endif
00249 
00250 
00251 
00252         /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
00253         for( ulData = 2; ulData < 5; ulData++ )
00254         {
00255             xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
00256         }
00257 
00258         /* Now the order in the queue should be 2, 3, 4, with 2 being the first
00259         thing to be read out.  Now add 1 then 0 to the front of the queue. */
00260         if( uxQueueMessagesWaiting( xQueue ) != 3 )
00261         {
00262             xErrorDetected = pdTRUE;
00263         }
00264         ulData = 1;
00265         xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
00266         ulData = 0;
00267         xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
00268 
00269         /* Now the queue should be full, and when we read the data out we
00270         should receive 0, 1, 2, 3, 4. */
00271         if( uxQueueMessagesWaiting( xQueue ) != 5 )
00272         {
00273             xErrorDetected = pdTRUE;
00274         }
00275 
00276         if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
00277         {
00278             xErrorDetected = pdTRUE;
00279         }
00280 
00281         if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
00282         {
00283             xErrorDetected = pdTRUE;
00284         }
00285 
00286         #if configUSE_PREEMPTION == 0
00287             taskYIELD();
00288         #endif
00289 
00290         /* Check the data we read out is in the expected order. */
00291         for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
00292         {
00293             /* Try peeking the data first. */
00294             if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
00295             {
00296                 xErrorDetected = pdTRUE;
00297             }
00298 
00299             if( ulData != ulData2 )
00300             {
00301                 xErrorDetected = pdTRUE;
00302             }
00303             
00304 
00305             /* Now try receiving the data for real.  The value should be the
00306             same.  Clobber the value first so we know we really received it. */
00307             ulData2 = ~ulData2;
00308             if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
00309             {
00310                 xErrorDetected = pdTRUE;
00311             }
00312 
00313             if( ulData != ulData2 )
00314             {
00315                 xErrorDetected = pdTRUE;
00316             }
00317         }
00318 
00319         /* The queue should now be empty again. */
00320         if( uxQueueMessagesWaiting( xQueue ) != 0 )
00321         {
00322             xErrorDetected = pdTRUE;
00323         }
00324 
00325         #if configUSE_PREEMPTION == 0
00326             taskYIELD();
00327         #endif
00328 
00329 
00330         /* Our queue is empty once more, add 10, 11 to the back. */
00331         ulData = 10;
00332         if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
00333         {
00334             xErrorDetected = pdTRUE;
00335         }
00336         ulData = 11;
00337         if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
00338         {
00339             xErrorDetected = pdTRUE;
00340         }
00341 
00342         if( uxQueueMessagesWaiting( xQueue ) != 2 )
00343         {
00344             xErrorDetected = pdTRUE;
00345         }
00346 
00347         /* Now we should have 10, 11 in the queue.  Add 7, 8, 9 to the
00348         front. */
00349         for( ulData = 9; ulData >= 7; ulData-- )
00350         {
00351             if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
00352             {
00353                 xErrorDetected = pdTRUE;
00354             }
00355         }
00356 
00357         /* Now check that the queue is full, and that receiving data provides
00358         the expected sequence of 7, 8, 9, 10, 11. */
00359         if( uxQueueMessagesWaiting( xQueue ) != 5 )
00360         {
00361             xErrorDetected = pdTRUE;
00362         }
00363 
00364         if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
00365         {
00366             xErrorDetected = pdTRUE;
00367         }
00368 
00369         if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
00370         {
00371             xErrorDetected = pdTRUE;
00372         }
00373 
00374         #if configUSE_PREEMPTION == 0
00375             taskYIELD();
00376         #endif
00377 
00378         /* Check the data we read out is in the expected order. */
00379         for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
00380         {
00381             if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
00382             {
00383                 xErrorDetected = pdTRUE;
00384             }
00385 
00386             if( ulData != ulData2 )
00387             {
00388                 xErrorDetected = pdTRUE;
00389             }
00390         }
00391 
00392         if( uxQueueMessagesWaiting( xQueue ) != 0 )
00393         {
00394             xErrorDetected = pdTRUE;
00395         }
00396 
00397         ulLoopCounter++;
00398     }
00399 }
00400 /*-----------------------------------------------------------*/
00401 
00402 static void prvLowPriorityMutexTask( void *pvParameters )
00403 {
00404 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
00405 
00406     #ifdef USE_STDIO
00407     void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
00408     
00409         const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
00410 
00411         /* Queue a message for printing to say the task has started. */
00412         vPrintDisplayMessage( &pcTaskStartMsg );
00413     #endif
00414 
00415     for( ;; )
00416     {
00417         /* Take the mutex.  It should be available now. */
00418         if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )
00419         {
00420             xErrorDetected = pdTRUE;
00421         }
00422 
00423         /* Set our guarded variable to a known start value. */
00424         ulGuardedVariable = 0;
00425 
00426         /* Our priority should be as per that assigned when the task was
00427         created. */
00428         if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
00429         {
00430             xErrorDetected = pdTRUE;
00431         }
00432 
00433         /* Now unsuspend the high priority task.  This will attempt to take the
00434         mutex, and block when it finds it cannot obtain it. */
00435         vTaskResume( xHighPriorityMutexTask );
00436 
00437         /* We should now have inherited the prioritoy of the high priority task,
00438         as by now it will have attempted to get the mutex. */
00439         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
00440         {
00441             xErrorDetected = pdTRUE;
00442         }
00443 
00444         /* We can attempt to set our priority to the test priority - between the
00445         idle priority and the medium/high test priorities, but our actual
00446         prioroity should remain at the high priority. */
00447         vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
00448         if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
00449         {
00450             xErrorDetected = pdTRUE;
00451         }
00452 
00453         /* Now unsuspend the medium priority task.  This should not run as our
00454         inherited priority is above that of the medium priority task. */
00455         vTaskResume( xMediumPriorityMutexTask );
00456 
00457         /* If the did run then it will have incremented our guarded variable. */
00458         if( ulGuardedVariable != 0 )
00459         {
00460             xErrorDetected = pdTRUE;
00461         }
00462 
00463         /* When we give back the semaphore our priority should be disinherited
00464         back to the priority to which we attempted to set ourselves.  This means
00465         that when the high priority task next blocks, the medium priority task
00466         should execute and increment the guarded variable.   When we next run
00467         both the high and medium priority tasks will have been suspended again. */
00468         if( xSemaphoreGive( xMutex ) != pdPASS )
00469         {
00470             xErrorDetected = pdTRUE;
00471         }
00472 
00473         /* Check that the guarded variable did indeed increment... */
00474         if( ulGuardedVariable != 1 )
00475         {
00476             xErrorDetected = pdTRUE;
00477         }
00478 
00479         /* ... and that our priority has been disinherited to
00480         genqMUTEX_TEST_PRIORITY. */
00481         if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
00482         {
00483             xErrorDetected = pdTRUE;
00484         }
00485 
00486         /* Set our priority back to our original priority ready for the next
00487         loop around this test. */
00488         vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
00489 
00490         /* Just to show we are still running. */
00491         ulLoopCounter2++;
00492 
00493         #if configUSE_PREEMPTION == 0
00494             taskYIELD();
00495         #endif        
00496     }
00497 }
00498 /*-----------------------------------------------------------*/
00499 
00500 static void prvMediumPriorityMutexTask( void *pvParameters )
00501 {
00502     ( void ) pvParameters;
00503 
00504     for( ;; )
00505     {
00506         /* The medium priority task starts by suspending itself.  The low
00507         priority task will unsuspend this task when required. */
00508         vTaskSuspend( NULL );
00509 
00510         /* When this task unsuspends all it does is increment the guarded
00511         variable, this is so the low priority task knows that it has
00512         executed. */
00513         ulGuardedVariable++;
00514     }
00515 }
00516 /*-----------------------------------------------------------*/
00517 
00518 static void prvHighPriorityMutexTask( void *pvParameters )
00519 {
00520 xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
00521 
00522     for( ;; )
00523     {
00524         /* The high priority task starts by suspending itself.  The low
00525         priority task will unsuspend this task when required. */
00526         vTaskSuspend( NULL );
00527 
00528         /* When this task unsuspends all it does is attempt to obtain
00529         the mutex.  It should find the mutex is not available so a
00530         block time is specified. */
00531         if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
00532         {
00533             xErrorDetected = pdTRUE;
00534         }
00535 
00536         /* When we eventually obtain the mutex we just give it back then
00537         return to suspend ready for the next test. */
00538         if( xSemaphoreGive( xMutex ) != pdPASS )
00539         {
00540             xErrorDetected = pdTRUE;
00541         }        
00542     }
00543 }
00544 /*-----------------------------------------------------------*/
00545 
00546 /* This is called to check that all the created tasks are still running. */
00547 portBASE_TYPE xAreGenericQueueTasksStillRunning( void )
00548 {
00549 static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
00550 
00551     /* If the demo task is still running then we expect the loopcounters to
00552     have incremented since this function was last called. */
00553     if( ulLastLoopCounter == ulLoopCounter )
00554     {
00555         xErrorDetected = pdTRUE;
00556     }
00557 
00558     if( ulLastLoopCounter2 == ulLoopCounter2 )
00559     {
00560         xErrorDetected = pdTRUE;
00561     }
00562 
00563     ulLastLoopCounter = ulLoopCounter;
00564     ulLastLoopCounter2 = ulLoopCounter2;    
00565 
00566     /* Errors detected in the task itself will have latched xErrorDetected
00567     to true. */
00568 
00569     return !xErrorDetected;
00570 }
00571 
00572