Rohit Grover / FreeRTOS

Dependents:   Nucleo freertos_test FreeRTOS_test freertos_bluetooth ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers croutine.c Source File

croutine.c

00001 /*
00002     FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
00003     All rights reserved
00004 
00005     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
00006 
00007     ***************************************************************************
00008      *                                                                       *
00009      *    FreeRTOS provides completely free yet professionally developed,    *
00010      *    robust, strictly quality controlled, supported, and cross          *
00011      *    platform software that has become a de facto standard.             *
00012      *                                                                       *
00013      *    Help yourself get started quickly and support the FreeRTOS         *
00014      *    project by purchasing a FreeRTOS tutorial book, reference          *
00015      *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
00016      *                                                                       *
00017      *    Thank you!                                                         *
00018      *                                                                       *
00019     ***************************************************************************
00020 
00021     This file is part of the FreeRTOS distribution.
00022 
00023     FreeRTOS is free software; you can redistribute it and/or modify it under
00024     the terms of the GNU General Public License (version 2) as published by the
00025     Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
00026 
00027     >>! NOTE: The modification to the GPL is included to allow you to distribute
00028     >>! a combined work that includes FreeRTOS without being obliged to provide
00029     >>! the source code for proprietary components outside of the FreeRTOS
00030     >>! kernel.
00031 
00032     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
00033     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00034     FOR A PARTICULAR PURPOSE.  Full license text is available from the following
00035     link: http://www.freertos.org/a00114.html
00036 
00037     1 tab == 4 spaces!
00038 
00039     ***************************************************************************
00040      *                                                                       *
00041      *    Having a problem?  Start by reading the FAQ "My application does   *
00042      *    not run, what could be wrong?"                                     *
00043      *                                                                       *
00044      *    http://www.FreeRTOS.org/FAQHelp.html                               *
00045      *                                                                       *
00046     ***************************************************************************
00047 
00048     http://www.FreeRTOS.org - Documentation, books, training, latest versions,
00049     license and Real Time Engineers Ltd. contact details.
00050 
00051     http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
00052     including FreeRTOS+Trace - an indispensable productivity tool, a DOS
00053     compatible FAT file system, and our tiny thread aware UDP/IP stack.
00054 
00055     http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
00056     Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
00057     licenses offer ticketed support, indemnification and middleware.
00058 
00059     http://www.SafeRTOS.com - High Integrity Systems also provide a safety
00060     engineered and independently SIL3 certified version for use in safety and
00061     mission critical applications that require provable dependability.
00062 
00063     1 tab == 4 spaces!
00064 */
00065 
00066 #include "FreeRTOS.h"
00067 #include "task.h"
00068 #include "croutine.h"
00069 
00070 /*
00071  * Some kernel aware debuggers require data to be viewed to be global, rather
00072  * than file scope.
00073  */
00074 #ifdef portREMOVE_STATIC_QUALIFIER
00075     #define static
00076 #endif
00077 
00078 
00079 /* Lists for ready and blocked co-routines. --------------------*/
00080 static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ];  /*< Prioritised ready co-routines. */
00081 static xList xDelayedCoRoutineList1;                                    /*< Delayed co-routines. */
00082 static xList xDelayedCoRoutineList2;                                    /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
00083 static xList * pxDelayedCoRoutineList;                                  /*< Points to the delayed co-routine list currently being used. */
00084 static xList * pxOverflowDelayedCoRoutineList;                          /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
00085 static xList xPendingReadyCoRoutineList;                                /*< Holds co-routines that have been readied by an external event.  They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
00086 
00087 /* Other file private variables. --------------------------------*/
00088 corCRCB * pxCurrentCoRoutine = NULL;
00089 static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
00090 static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
00091 
00092 /* The initial state of the co-routine when it is created. */
00093 #define corINITIAL_STATE    ( 0 )
00094 
00095 /*
00096  * Place the co-routine represented by pxCRCB into the appropriate ready queue
00097  * for the priority.  It is inserted at the end of the list.
00098  *
00099  * This macro accesses the co-routine ready lists and therefore must not be
00100  * used from within an ISR.
00101  */
00102 #define prvAddCoRoutineToReadyQueue( pxCRCB )                                                                       \
00103 {                                                                                                                   \
00104     if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority )                                                          \
00105     {                                                                                                               \
00106         uxTopCoRoutineReadyPriority = pxCRCB->uxPriority;                                                           \
00107     }                                                                                                               \
00108     vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) );  \
00109 }
00110 
00111 /*
00112  * Utility to ready all the lists used by the scheduler.  This is called
00113  * automatically upon the creation of the first co-routine.
00114  */
00115 static void prvInitialiseCoRoutineLists( void );
00116 
00117 /*
00118  * Co-routines that are readied by an interrupt cannot be placed directly into
00119  * the ready lists (there is no mutual exclusion).  Instead they are placed in
00120  * in the pending ready list in order that they can later be moved to the ready
00121  * list by the co-routine scheduler.
00122  */
00123 static void prvCheckPendingReadyList( void );
00124 
00125 /*
00126  * Macro that looks at the list of co-routines that are currently delayed to
00127  * see if any require waking.
00128  *
00129  * Co-routines are stored in the queue in the order of their wake time -
00130  * meaning once one co-routine has been found whose timer has not expired
00131  * we need not look any further down the list.
00132  */
00133 static void prvCheckDelayedList( void );
00134 
00135 /*-----------------------------------------------------------*/
00136 
00137 signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
00138 {
00139 signed portBASE_TYPE xReturn;
00140 corCRCB *pxCoRoutine;
00141 
00142     /* Allocate the memory that will store the co-routine control block. */
00143     pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
00144     if( pxCoRoutine )
00145     {
00146         /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
00147         be created and the co-routine data structures need initialising. */
00148         if( pxCurrentCoRoutine == NULL )
00149         {
00150             pxCurrentCoRoutine = pxCoRoutine;
00151             prvInitialiseCoRoutineLists();
00152         }
00153 
00154         /* Check the priority is within limits. */
00155         if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
00156         {
00157             uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
00158         }
00159 
00160         /* Fill out the co-routine control block from the function parameters. */
00161         pxCoRoutine->uxState = corINITIAL_STATE;
00162         pxCoRoutine->uxPriority = uxPriority;
00163         pxCoRoutine->uxIndex = uxIndex;
00164         pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
00165 
00166         /* Initialise all the other co-routine control block parameters. */
00167         vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
00168         vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
00169 
00170         /* Set the co-routine control block as a link back from the xListItem.
00171         This is so we can get back to the containing CRCB from a generic item
00172         in a list. */
00173         listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
00174         listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
00175 
00176         /* Event lists are always in priority order. */
00177         listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
00178 
00179         /* Now the co-routine has been initialised it can be added to the ready
00180         list at the correct priority. */
00181         prvAddCoRoutineToReadyQueue( pxCoRoutine );
00182 
00183         xReturn = pdPASS;
00184     }
00185     else
00186     {
00187         xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
00188     }
00189 
00190     return xReturn;
00191 }
00192 /*-----------------------------------------------------------*/
00193 
00194 void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
00195 {
00196 portTickType xTimeToWake;
00197 
00198     /* Calculate the time to wake - this may overflow but this is
00199     not a problem. */
00200     xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
00201 
00202     /* We must remove ourselves from the ready list before adding
00203     ourselves to the blocked list as the same list item is used for
00204     both lists. */
00205     ( void ) uxListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
00206 
00207     /* The list item will be inserted in wake time order. */
00208     listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
00209 
00210     if( xTimeToWake < xCoRoutineTickCount )
00211     {
00212         /* Wake time has overflowed.  Place this item in the
00213         overflow list. */
00214         vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
00215     }
00216     else
00217     {
00218         /* The wake time has not overflowed, so we can use the
00219         current block list. */
00220         vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
00221     }
00222 
00223     if( pxEventList )
00224     {
00225         /* Also add the co-routine to an event list.  If this is done then the
00226         function must be called with interrupts disabled. */
00227         vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
00228     }
00229 }
00230 /*-----------------------------------------------------------*/
00231 
00232 static void prvCheckPendingReadyList( void )
00233 {
00234     /* Are there any co-routines waiting to get moved to the ready list?  These
00235     are co-routines that have been readied by an ISR.  The ISR cannot access
00236     the ready lists itself. */
00237     while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
00238     {
00239         corCRCB *pxUnblockedCRCB;
00240 
00241         /* The pending ready list can be accessed by an ISR. */
00242         portDISABLE_INTERRUPTS();
00243         {
00244             pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
00245             ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
00246         }
00247         portENABLE_INTERRUPTS();
00248 
00249         ( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
00250         prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
00251     }
00252 }
00253 /*-----------------------------------------------------------*/
00254 
00255 static void prvCheckDelayedList( void )
00256 {
00257 corCRCB *pxCRCB;
00258 
00259     xPassedTicks = xTaskGetTickCount() - xLastTickCount;
00260     while( xPassedTicks )
00261     {
00262         xCoRoutineTickCount++;
00263         xPassedTicks--;
00264 
00265         /* If the tick count has overflowed we need to swap the ready lists. */
00266         if( xCoRoutineTickCount == 0 )
00267         {
00268             xList * pxTemp;
00269 
00270             /* Tick count has overflowed so we need to swap the delay lists.  If there are
00271             any items in pxDelayedCoRoutineList here then there is an error! */
00272             pxTemp = pxDelayedCoRoutineList;
00273             pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
00274             pxOverflowDelayedCoRoutineList = pxTemp;
00275         }
00276 
00277         /* See if this tick has made a timeout expire. */
00278         while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
00279         {
00280             pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
00281 
00282             if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
00283             {
00284                 /* Timeout not yet expired. */
00285                 break;
00286             }
00287 
00288             portDISABLE_INTERRUPTS();
00289             {
00290                 /* The event could have occurred just before this critical
00291                 section.  If this is the case then the generic list item will
00292                 have been moved to the pending ready list and the following
00293                 line is still valid.  Also the pvContainer parameter will have
00294                 been set to NULL so the following lines are also valid. */
00295                 uxListRemove( &( pxCRCB->xGenericListItem ) );
00296 
00297                 /* Is the co-routine waiting on an event also? */
00298                 if( pxCRCB->xEventListItem.pvContainer )
00299                 {
00300                     ( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
00301                 }
00302             }
00303             portENABLE_INTERRUPTS();
00304 
00305             prvAddCoRoutineToReadyQueue( pxCRCB );
00306         }
00307     }
00308 
00309     xLastTickCount = xCoRoutineTickCount;
00310 }
00311 /*-----------------------------------------------------------*/
00312 
00313 void vCoRoutineSchedule( void )
00314 {
00315     /* See if any co-routines readied by events need moving to the ready lists. */
00316     prvCheckPendingReadyList();
00317 
00318     /* See if any delayed co-routines have timed out. */
00319     prvCheckDelayedList();
00320 
00321     /* Find the highest priority queue that contains ready co-routines. */
00322     while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
00323     {
00324         if( uxTopCoRoutineReadyPriority == 0 )
00325         {
00326             /* No more co-routines to check. */
00327             return;
00328         }
00329         --uxTopCoRoutineReadyPriority;
00330     }
00331 
00332     /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
00333      of the same priority get an equal share of the processor time. */
00334     listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
00335 
00336     /* Call the co-routine. */
00337     ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
00338 
00339     return;
00340 }
00341 /*-----------------------------------------------------------*/
00342 
00343 static void prvInitialiseCoRoutineLists( void )
00344 {
00345 unsigned portBASE_TYPE uxPriority;
00346 
00347     for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
00348     {
00349         vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
00350     }
00351 
00352     vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
00353     vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
00354     vListInitialise( ( xList * ) &xPendingReadyCoRoutineList );
00355 
00356     /* Start with pxDelayedCoRoutineList using list1 and the
00357     pxOverflowDelayedCoRoutineList using list2. */
00358     pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
00359     pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
00360 }
00361 /*-----------------------------------------------------------*/
00362 
00363 signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
00364 {
00365 corCRCB *pxUnblockedCRCB;
00366 signed portBASE_TYPE xReturn;
00367 
00368     /* This function is called from within an interrupt.  It can only access
00369     event lists and the pending ready list.  This function assumes that a
00370     check has already been made to ensure pxEventList is not empty. */
00371     pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
00372     ( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
00373     vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
00374 
00375     if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
00376     {
00377         xReturn = pdTRUE;
00378     }
00379     else
00380     {
00381         xReturn = pdFALSE;
00382     }
00383 
00384     return xReturn;
00385 }
00386