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 QPeek.c Source File

QPeek.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 behaviour when data is peeked from a queue when there are
00057  * multiple tasks blocked on the queue.
00058  */
00059 
00060 
00061 #include <stdlib.h>
00062 
00063 /* Scheduler include files. */
00064 #include "FreeRTOS.h"
00065 #include "task.h"
00066 #include "queue.h"
00067 #include "semphr.h"
00068 
00069 /* Demo program include files. */
00070 #include "QPeek.h"
00071 
00072 #define qpeekQUEUE_LENGTH        ( 5 )
00073 #define qpeekNO_BLOCK            ( 0 )
00074 #define qpeekSHORT_DELAY        ( 10 )
00075 
00076 #define qpeekLOW_PRIORITY            ( tskIDLE_PRIORITY + 0 )
00077 #define qpeekMEDIUM_PRIORITY        ( tskIDLE_PRIORITY + 1 )
00078 #define qpeekHIGH_PRIORITY            ( tskIDLE_PRIORITY + 2 )
00079 #define qpeekHIGHEST_PRIORITY        ( tskIDLE_PRIORITY + 3 )
00080 
00081 /*-----------------------------------------------------------*/
00082 
00083 /*
00084  * The following three tasks are used to demonstrate the peeking behaviour.
00085  * Each task is given a different priority to demonstrate the order in which
00086  * tasks are woken as data is peeked from a queue.
00087  */
00088 static void prvLowPriorityPeekTask( void *pvParameters );
00089 static void prvMediumPriorityPeekTask( void *pvParameters );
00090 static void prvHighPriorityPeekTask( void *pvParameters );
00091 static void prvHighestPriorityPeekTask( void *pvParameters );
00092 
00093 /*-----------------------------------------------------------*/
00094 
00095 /* Flag that will be latched to pdTRUE should any unexpected behaviour be
00096 detected in any of the tasks. */
00097 static volatile portBASE_TYPE xErrorDetected = pdFALSE;
00098 
00099 /* Counter that is incremented on each cycle of a test.  This is used to
00100 detect a stalled task - a test that is no longer running. */
00101 static volatile unsigned portLONG ulLoopCounter = 0;
00102 
00103 /* Handles to the test tasks. */
00104 xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
00105 /*-----------------------------------------------------------*/
00106 
00107 void vStartQueuePeekTasks( void )
00108 {
00109 xQueueHandle xQueue;
00110 
00111     /* Create the queue that we are going to use for the test/demo. */
00112     xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( unsigned portLONG ) );
00113 
00114     /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
00115     in use.  The queue registry is provided as a means for kernel aware 
00116     debuggers to locate queues and has no purpose if a kernel aware debugger
00117     is not being used.  The call to vQueueAddToRegistry() will be removed
00118     by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is 
00119     defined to be less than 1. */
00120     vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "QPeek_Test_Queue" );
00121 
00122     /* Create the demo tasks and pass it the queue just created.  We are
00123     passing the queue handle by value so it does not matter that it is declared
00124     on the stack here. */
00125     xTaskCreate( prvLowPriorityPeekTask, ( signed portCHAR * )"PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
00126     xTaskCreate( prvMediumPriorityPeekTask, ( signed portCHAR * )"PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
00127     xTaskCreate( prvHighPriorityPeekTask, ( signed portCHAR * )"PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
00128     xTaskCreate( prvHighestPriorityPeekTask, ( signed portCHAR * )"PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );
00129 }
00130 /*-----------------------------------------------------------*/
00131 
00132 static void prvHighestPriorityPeekTask( void *pvParameters )
00133 {
00134 xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
00135 unsigned portLONG ulValue;
00136 
00137     #ifdef USE_STDIO
00138     {
00139         void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
00140     
00141         const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n";
00142 
00143         /* Queue a message for printing to say the task has started. */
00144         vPrintDisplayMessage( &pcTaskStartMsg );
00145     }
00146     #endif
00147 
00148     for( ;; )
00149     {
00150         /* Try peeking from the queue.  The queue should be empty so we will
00151         block, allowing the high priority task to execute. */
00152         if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
00153         {
00154             /* We expected to have received something by the time we unblock. */
00155             xErrorDetected = pdTRUE;
00156         }
00157 
00158         /* When we reach here the high and medium priority tasks should still
00159         be blocked on the queue.  We unblocked because the low priority task
00160         wrote a value to the queue, which we should have peeked.  Peeking the
00161         data (rather than receiving it) will leave the data on the queue, so
00162         the high priority task should then have also been unblocked, but not
00163         yet executed. */
00164         if( ulValue != 0x11223344 )
00165         {
00166             /* We did not receive the expected value. */
00167             xErrorDetected = pdTRUE;
00168         }
00169 
00170         if( uxQueueMessagesWaiting( xQueue ) != 1 )
00171         {
00172             /* The message should have been left on the queue. */
00173             xErrorDetected = pdTRUE;
00174         }
00175 
00176         /* Now we are going to actually receive the data, so when the high
00177         priority task runs it will find the queue empty and return to the
00178         blocked state. */
00179         ulValue = 0;
00180         if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
00181         {
00182             /* We expected to receive the value. */
00183             xErrorDetected = pdTRUE;
00184         }
00185 
00186         if( ulValue != 0x11223344 )
00187         {
00188             /* We did not receive the expected value - which should have been
00189             the same value as was peeked. */
00190             xErrorDetected = pdTRUE;
00191         }
00192 
00193         /* Now we will block again as the queue is once more empty.  The low 
00194         priority task can then execute again. */
00195         if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
00196         {
00197             /* We expected to have received something by the time we unblock. */
00198             xErrorDetected = pdTRUE;
00199         }
00200 
00201         /* When we get here the low priority task should have again written to the
00202         queue. */
00203         if( ulValue != 0x01234567 )
00204         {
00205             /* We did not receive the expected value. */
00206             xErrorDetected = pdTRUE;
00207         }
00208 
00209         if( uxQueueMessagesWaiting( xQueue ) != 1 )
00210         {
00211             /* The message should have been left on the queue. */
00212             xErrorDetected = pdTRUE;
00213         }
00214 
00215         /* We only peeked the data, so suspending ourselves now should enable
00216         the high priority task to also peek the data.  The high priority task
00217         will have been unblocked when we peeked the data as we left the data
00218         in the queue. */
00219         vTaskSuspend( NULL );
00220 
00221 
00222 
00223         /* This time we are going to do the same as the above test, but the
00224         high priority task is going to receive the data, rather than peek it.
00225         This means that the medium priority task should never peek the value. */
00226         if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
00227         {
00228             xErrorDetected = pdTRUE;
00229         }
00230 
00231         if( ulValue != 0xaabbaabb )
00232         {
00233             xErrorDetected = pdTRUE;
00234         }
00235 
00236         vTaskSuspend( NULL );        
00237     }
00238 }
00239 /*-----------------------------------------------------------*/
00240 
00241 static void prvHighPriorityPeekTask( void *pvParameters )
00242 {
00243 xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
00244 unsigned portLONG ulValue;
00245 
00246     for( ;; )
00247     {
00248         /* Try peeking from the queue.  The queue should be empty so we will
00249         block, allowing the medium priority task to execute.  Both the high
00250         and highest priority tasks will then be blocked on the queue. */
00251         if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
00252         {
00253             /* We expected to have received something by the time we unblock. */
00254             xErrorDetected = pdTRUE;
00255         }
00256 
00257         /* When we get here the highest priority task should have peeked the data
00258         (unblocking this task) then suspended (allowing this task to also peek
00259         the data). */
00260         if( ulValue != 0x01234567 )
00261         {
00262             /* We did not receive the expected value. */
00263             xErrorDetected = pdTRUE;
00264         }
00265 
00266         if( uxQueueMessagesWaiting( xQueue ) != 1 )
00267         {
00268             /* The message should have been left on the queue. */
00269             xErrorDetected = pdTRUE;
00270         }
00271 
00272         /* We only peeked the data, so suspending ourselves now should enable
00273         the medium priority task to also peek the data.  The medium priority task
00274         will have been unblocked when we peeked the data as we left the data
00275         in the queue. */
00276         vTaskSuspend( NULL );
00277 
00278 
00279         /* This time we are going actually receive the value, so the medium
00280         priority task will never peek the data - we removed it from the queue. */
00281         if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
00282         {
00283             xErrorDetected = pdTRUE;
00284         }
00285 
00286         if( ulValue != 0xaabbaabb )
00287         {
00288             xErrorDetected = pdTRUE;
00289         }
00290 
00291         vTaskSuspend( NULL );                
00292     }
00293 }
00294 /*-----------------------------------------------------------*/
00295 
00296 static void prvMediumPriorityPeekTask( void *pvParameters )
00297 {
00298 xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
00299 unsigned portLONG ulValue;
00300 
00301     for( ;; )
00302     {
00303         /* Try peeking from the queue.  The queue should be empty so we will
00304         block, allowing the low priority task to execute.  The highest, high
00305         and medium priority tasks will then all be blocked on the queue. */
00306         if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
00307         {
00308             /* We expected to have received something by the time we unblock. */
00309             xErrorDetected = pdTRUE;
00310         }
00311 
00312         /* When we get here the high priority task should have peeked the data
00313         (unblocking this task) then suspended (allowing this task to also peek
00314         the data). */
00315         if( ulValue != 0x01234567 )
00316         {
00317             /* We did not receive the expected value. */
00318             xErrorDetected = pdTRUE;
00319         }
00320 
00321         if( uxQueueMessagesWaiting( xQueue ) != 1 )
00322         {
00323             /* The message should have been left on the queue. */
00324             xErrorDetected = pdTRUE;
00325         }
00326 
00327         /* Just so we know the test is still running. */
00328         ulLoopCounter++;
00329 
00330         /* Now we can suspend ourselves so the low priority task can execute
00331         again. */
00332         vTaskSuspend( NULL );
00333     }
00334 }
00335 /*-----------------------------------------------------------*/
00336 
00337 static void prvLowPriorityPeekTask( void *pvParameters )
00338 {
00339 xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
00340 unsigned portLONG ulValue;
00341 
00342     for( ;; )
00343     {
00344         /* Write some data to the queue.  This should unblock the highest 
00345         priority task that is waiting to peek data from the queue. */
00346         ulValue = 0x11223344;
00347         if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
00348         {
00349             /* We were expecting the queue to be empty so we should not of
00350             had a problem writing to the queue. */
00351             xErrorDetected = pdTRUE;
00352         }
00353 
00354         /* By the time we get here the data should have been removed from
00355         the queue. */
00356         if( uxQueueMessagesWaiting( xQueue ) != 0 )
00357         {
00358             xErrorDetected = pdTRUE;
00359         }
00360 
00361         /* Write another value to the queue, again waking the highest priority
00362         task that is blocked on the queue. */
00363         ulValue = 0x01234567;
00364         if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
00365         {
00366             /* We were expecting the queue to be empty so we should not of
00367             had a problem writing to the queue. */
00368             xErrorDetected = pdTRUE;
00369         }
00370 
00371         /* All the other tasks should now have successfully peeked the data.
00372         The data is still in the queue so we should be able to receive it. */
00373         ulValue = 0;
00374         if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
00375         {
00376             /* We expected to receive the data. */
00377             xErrorDetected = pdTRUE;
00378         }
00379 
00380         if( ulValue != 0x01234567 )
00381         {
00382             /* We did not receive the expected value. */
00383         }
00384         
00385         /* Lets just delay a while as this is an intensive test as we don't
00386         want to starve other tests of processing time. */
00387         vTaskDelay( qpeekSHORT_DELAY );
00388 
00389         /* Unsuspend the other tasks so we can repeat the test - this time
00390         however not all the other tasks will peek the data as the high
00391         priority task is actually going to remove it from the queue.  Send
00392         to front is used just to be different.  As the queue is empty it
00393         makes no difference to the result. */
00394         vTaskResume( xMediumPriorityTask );
00395         vTaskResume( xHighPriorityTask );
00396         vTaskResume( xHighestPriorityTask );
00397 
00398         ulValue = 0xaabbaabb;
00399         if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
00400         {
00401             /* We were expecting the queue to be empty so we should not of
00402             had a problem writing to the queue. */
00403             xErrorDetected = pdTRUE;
00404         }
00405 
00406         /* This time we should find that the queue is empty.  The high priority
00407         task actually removed the data rather than just peeking it. */
00408         if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
00409         {
00410             /* We expected to receive the data. */
00411             xErrorDetected = pdTRUE;
00412         }
00413 
00414         /* Unsuspend the highest and high priority tasks so we can go back
00415         and repeat the whole thing.  The medium priority task should not be
00416         suspended as it was not able to peek the data in this last case. */
00417         vTaskResume( xHighPriorityTask );
00418         vTaskResume( xHighestPriorityTask );        
00419 
00420         /* Lets just delay a while as this is an intensive test as we don't
00421         want to starve other tests of processing time. */
00422         vTaskDelay( qpeekSHORT_DELAY );
00423     }
00424 }
00425 /*-----------------------------------------------------------*/
00426 
00427 /* This is called to check that all the created tasks are still running. */
00428 portBASE_TYPE xAreQueuePeekTasksStillRunning( void )
00429 {
00430 static unsigned portLONG ulLastLoopCounter = 0;
00431 
00432     /* If the demo task is still running then we expect the loopcounter to
00433     have incremented since this function was last called. */
00434     if( ulLastLoopCounter == ulLoopCounter )
00435     {
00436         xErrorDetected = pdTRUE;
00437     }
00438 
00439     ulLastLoopCounter = ulLoopCounter;
00440 
00441     /* Errors detected in the task itself will have latched xErrorDetected
00442     to true. */
00443 
00444     return !xErrorDetected;
00445 }
00446