2013-04-05 23:59:28 +02:00
/*
2014-06-10 19:42:11 +02:00
FreeRTOS V8 .0 .1 - Copyright ( C ) 2014 Real Time Engineers Ltd .
2014-03-23 18:44:06 +01:00
All rights reserved
2013-04-05 23:59:28 +02:00
2013-09-05 05:26:23 +02:00
VISIT http : //www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
2013-04-05 23:59:28 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
2013-09-05 05:26:23 +02:00
* FreeRTOS provides completely free yet professionally developed , *
* robust , strictly quality controlled , supported , and cross *
* platform software that has become a de facto standard . *
2013-04-05 23:59:28 +02:00
* *
2013-09-05 05:26:23 +02:00
* Help yourself get started quickly and support the FreeRTOS *
* project by purchasing a FreeRTOS tutorial book , reference *
* manual , or both from : http : //www.FreeRTOS.org/Documentation *
2013-04-05 23:59:28 +02:00
* *
2013-09-05 05:26:23 +02:00
* Thank you ! *
2013-04-05 23:59:28 +02:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
This file is part of the FreeRTOS distribution .
FreeRTOS is free software ; you can redistribute it and / or modify it under
the terms of the GNU General Public License ( version 2 ) as published by the
2013-09-05 05:26:23 +02:00
Free Software Foundation > > ! AND MODIFIED BY ! < < the FreeRTOS exception .
2013-04-05 23:59:28 +02:00
2014-06-10 19:42:11 +02:00
> > ! NOTE : The modification to the GPL is included to allow you to ! < <
> > ! distribute a combined work that includes FreeRTOS without being ! < <
> > ! obliged to provide the source code for proprietary components ! < <
> > ! outside of the FreeRTOS kernel . ! < <
2013-04-05 23:59:28 +02:00
FreeRTOS is distributed in the hope that it will be useful , but WITHOUT ANY
WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
2013-09-05 05:26:23 +02:00
FOR A PARTICULAR PURPOSE . Full license text is available from the following
link : http : //www.freertos.org/a00114.html
2013-04-05 23:59:28 +02:00
1 tab = = 4 spaces !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Having a problem ? Start by reading the FAQ " My application does *
* not run , what could be wrong ? " *
* *
* http : //www.FreeRTOS.org/FAQHelp.html *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
http : //www.FreeRTOS.org - Documentation, books, training, latest versions,
license and Real Time Engineers Ltd . contact details .
http : //www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
2013-09-05 05:26:23 +02:00
including FreeRTOS + Trace - an indispensable productivity tool , a DOS
compatible FAT file system , and our tiny thread aware UDP / IP stack .
2013-04-05 23:59:28 +02:00
http : //www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
2013-09-05 05:26:23 +02:00
Integrity Systems to sell under the OpenRTOS brand . Low cost OpenRTOS
licenses offer ticketed support , indemnification and middleware .
2013-04-05 23:59:28 +02:00
http : //www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability .
2013-09-05 05:26:23 +02:00
1 tab = = 4 spaces !
2013-04-05 23:59:28 +02:00
*/
# include "FreeRTOS.h"
# include "task.h"
# include "croutine.h"
/*
* Some kernel aware debuggers require data to be viewed to be global , rather
* than file scope .
*/
# ifdef portREMOVE_STATIC_QUALIFIER
# define static
# endif
/* Lists for ready and blocked co-routines. --------------------*/
2014-03-23 18:44:06 +01:00
static List_t pxReadyCoRoutineLists [ configMAX_CO_ROUTINE_PRIORITIES ] ; /*< Prioritised ready co-routines. */
static List_t xDelayedCoRoutineList1 ; /*< Delayed co-routines. */
static List_t xDelayedCoRoutineList2 ; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
static List_t * pxDelayedCoRoutineList ; /*< Points to the delayed co-routine list currently being used. */
static List_t * pxOverflowDelayedCoRoutineList ; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
static List_t 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. */
2013-04-05 23:59:28 +02:00
/* Other file private variables. --------------------------------*/
2014-03-23 18:44:06 +01:00
CRCB_t * pxCurrentCoRoutine = NULL ;
static UBaseType_t uxTopCoRoutineReadyPriority = 0 ;
static TickType_t xCoRoutineTickCount = 0 , xLastTickCount = 0 , xPassedTicks = 0 ;
2013-04-05 23:59:28 +02:00
/* The initial state of the co-routine when it is created. */
# define corINITIAL_STATE ( 0 )
/*
* Place the co - routine represented by pxCRCB into the appropriate ready queue
* for the priority . It is inserted at the end of the list .
*
* This macro accesses the co - routine ready lists and therefore must not be
* used from within an ISR .
*/
# define prvAddCoRoutineToReadyQueue( pxCRCB ) \
{ \
if ( pxCRCB - > uxPriority > uxTopCoRoutineReadyPriority ) \
{ \
uxTopCoRoutineReadyPriority = pxCRCB - > uxPriority ; \
} \
2014-03-23 18:44:06 +01:00
vListInsertEnd ( ( List_t * ) & ( pxReadyCoRoutineLists [ pxCRCB - > uxPriority ] ) , & ( pxCRCB - > xGenericListItem ) ) ; \
2013-04-05 23:59:28 +02:00
}
/*
* Utility to ready all the lists used by the scheduler . This is called
* automatically upon the creation of the first co - routine .
*/
static void prvInitialiseCoRoutineLists ( void ) ;
/*
* Co - routines that are readied by an interrupt cannot be placed directly into
* the ready lists ( there is no mutual exclusion ) . Instead they are placed in
* in the pending ready list in order that they can later be moved to the ready
* list by the co - routine scheduler .
*/
static void prvCheckPendingReadyList ( void ) ;
/*
* Macro that looks at the list of co - routines that are currently delayed to
* see if any require waking .
*
* Co - routines are stored in the queue in the order of their wake time -
* meaning once one co - routine has been found whose timer has not expired
* we need not look any further down the list .
*/
static void prvCheckDelayedList ( void ) ;
/*-----------------------------------------------------------*/
2014-03-23 18:44:06 +01:00
BaseType_t xCoRoutineCreate ( crCOROUTINE_CODE pxCoRoutineCode , UBaseType_t uxPriority , UBaseType_t uxIndex )
2013-04-05 23:59:28 +02:00
{
2014-03-23 18:44:06 +01:00
BaseType_t xReturn ;
CRCB_t * pxCoRoutine ;
2013-04-05 23:59:28 +02:00
/* Allocate the memory that will store the co-routine control block. */
2014-03-23 18:44:06 +01:00
pxCoRoutine = ( CRCB_t * ) pvPortMalloc ( sizeof ( CRCB_t ) ) ;
2013-04-05 23:59:28 +02:00
if ( pxCoRoutine )
{
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
be created and the co - routine data structures need initialising . */
if ( pxCurrentCoRoutine = = NULL )
{
pxCurrentCoRoutine = pxCoRoutine ;
prvInitialiseCoRoutineLists ( ) ;
}
/* Check the priority is within limits. */
if ( uxPriority > = configMAX_CO_ROUTINE_PRIORITIES )
{
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1 ;
}
/* Fill out the co-routine control block from the function parameters. */
pxCoRoutine - > uxState = corINITIAL_STATE ;
pxCoRoutine - > uxPriority = uxPriority ;
pxCoRoutine - > uxIndex = uxIndex ;
pxCoRoutine - > pxCoRoutineFunction = pxCoRoutineCode ;
/* Initialise all the other co-routine control block parameters. */
vListInitialiseItem ( & ( pxCoRoutine - > xGenericListItem ) ) ;
vListInitialiseItem ( & ( pxCoRoutine - > xEventListItem ) ) ;
2014-03-23 18:44:06 +01:00
/* Set the co-routine control block as a link back from the ListItem_t.
2013-04-05 23:59:28 +02:00
This is so we can get back to the containing CRCB from a generic item
in a list . */
listSET_LIST_ITEM_OWNER ( & ( pxCoRoutine - > xGenericListItem ) , pxCoRoutine ) ;
listSET_LIST_ITEM_OWNER ( & ( pxCoRoutine - > xEventListItem ) , pxCoRoutine ) ;
/* Event lists are always in priority order. */
2014-03-23 18:44:06 +01:00
listSET_LIST_ITEM_VALUE ( & ( pxCoRoutine - > xEventListItem ) , ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) ) ;
2013-04-05 23:59:28 +02:00
/* Now the co-routine has been initialised it can be added to the ready
list at the correct priority . */
prvAddCoRoutineToReadyQueue ( pxCoRoutine ) ;
xReturn = pdPASS ;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
2014-03-23 18:44:06 +01:00
void vCoRoutineAddToDelayedList ( TickType_t xTicksToDelay , List_t * pxEventList )
2013-04-05 23:59:28 +02:00
{
2014-03-23 18:44:06 +01:00
TickType_t xTimeToWake ;
2013-04-05 23:59:28 +02:00
/* Calculate the time to wake - this may overflow but this is
not a problem . */
xTimeToWake = xCoRoutineTickCount + xTicksToDelay ;
/* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for
both lists . */
2014-03-23 18:44:06 +01:00
( void ) uxListRemove ( ( ListItem_t * ) & ( pxCurrentCoRoutine - > xGenericListItem ) ) ;
2013-04-05 23:59:28 +02:00
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE ( & ( pxCurrentCoRoutine - > xGenericListItem ) , xTimeToWake ) ;
if ( xTimeToWake < xCoRoutineTickCount )
{
/* Wake time has overflowed. Place this item in the
overflow list . */
2014-03-23 18:44:06 +01:00
vListInsert ( ( List_t * ) pxOverflowDelayedCoRoutineList , ( ListItem_t * ) & ( pxCurrentCoRoutine - > xGenericListItem ) ) ;
2013-04-05 23:59:28 +02:00
}
else
{
/* The wake time has not overflowed, so we can use the
current block list . */
2014-03-23 18:44:06 +01:00
vListInsert ( ( List_t * ) pxDelayedCoRoutineList , ( ListItem_t * ) & ( pxCurrentCoRoutine - > xGenericListItem ) ) ;
2013-04-05 23:59:28 +02:00
}
if ( pxEventList )
{
/* Also add the co-routine to an event list. If this is done then the
function must be called with interrupts disabled . */
vListInsert ( pxEventList , & ( pxCurrentCoRoutine - > xEventListItem ) ) ;
}
}
/*-----------------------------------------------------------*/
static void prvCheckPendingReadyList ( void )
{
/* Are there any co-routines waiting to get moved to the ready list? These
are co - routines that have been readied by an ISR . The ISR cannot access
the ready lists itself . */
while ( listLIST_IS_EMPTY ( & xPendingReadyCoRoutineList ) = = pdFALSE )
{
2014-03-23 18:44:06 +01:00
CRCB_t * pxUnblockedCRCB ;
2013-04-05 23:59:28 +02:00
/* The pending ready list can be accessed by an ISR. */
portDISABLE_INTERRUPTS ( ) ;
{
2014-03-23 18:44:06 +01:00
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY ( ( & xPendingReadyCoRoutineList ) ) ;
2013-09-05 05:26:23 +02:00
( void ) uxListRemove ( & ( pxUnblockedCRCB - > xEventListItem ) ) ;
2013-04-05 23:59:28 +02:00
}
portENABLE_INTERRUPTS ( ) ;
2013-09-05 05:26:23 +02:00
( void ) uxListRemove ( & ( pxUnblockedCRCB - > xGenericListItem ) ) ;
2013-04-05 23:59:28 +02:00
prvAddCoRoutineToReadyQueue ( pxUnblockedCRCB ) ;
}
}
/*-----------------------------------------------------------*/
static void prvCheckDelayedList ( void )
{
2014-03-23 18:44:06 +01:00
CRCB_t * pxCRCB ;
2013-04-05 23:59:28 +02:00
xPassedTicks = xTaskGetTickCount ( ) - xLastTickCount ;
while ( xPassedTicks )
{
xCoRoutineTickCount + + ;
xPassedTicks - - ;
/* If the tick count has overflowed we need to swap the ready lists. */
if ( xCoRoutineTickCount = = 0 )
{
2014-03-23 18:44:06 +01:00
List_t * pxTemp ;
2013-04-05 23:59:28 +02:00
/* Tick count has overflowed so we need to swap the delay lists. If there are
any items in pxDelayedCoRoutineList here then there is an error ! */
pxTemp = pxDelayedCoRoutineList ;
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList ;
pxOverflowDelayedCoRoutineList = pxTemp ;
}
/* See if this tick has made a timeout expire. */
while ( listLIST_IS_EMPTY ( pxDelayedCoRoutineList ) = = pdFALSE )
{
2014-03-23 18:44:06 +01:00
pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY ( pxDelayedCoRoutineList ) ;
2013-04-05 23:59:28 +02:00
if ( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE ( & ( pxCRCB - > xGenericListItem ) ) )
{
/* Timeout not yet expired. */
break ;
}
portDISABLE_INTERRUPTS ( ) ;
{
/* The event could have occurred just before this critical
section . If this is the case then the generic list item will
have been moved to the pending ready list and the following
line is still valid . Also the pvContainer parameter will have
been set to NULL so the following lines are also valid . */
2014-06-10 19:42:11 +02:00
( void ) uxListRemove ( & ( pxCRCB - > xGenericListItem ) ) ;
2013-04-05 23:59:28 +02:00
/* Is the co-routine waiting on an event also? */
if ( pxCRCB - > xEventListItem . pvContainer )
{
2013-09-05 05:26:23 +02:00
( void ) uxListRemove ( & ( pxCRCB - > xEventListItem ) ) ;
2013-04-05 23:59:28 +02:00
}
}
portENABLE_INTERRUPTS ( ) ;
prvAddCoRoutineToReadyQueue ( pxCRCB ) ;
}
}
xLastTickCount = xCoRoutineTickCount ;
}
/*-----------------------------------------------------------*/
void vCoRoutineSchedule ( void )
{
/* See if any co-routines readied by events need moving to the ready lists. */
prvCheckPendingReadyList ( ) ;
/* See if any delayed co-routines have timed out. */
prvCheckDelayedList ( ) ;
/* Find the highest priority queue that contains ready co-routines. */
while ( listLIST_IS_EMPTY ( & ( pxReadyCoRoutineLists [ uxTopCoRoutineReadyPriority ] ) ) )
{
if ( uxTopCoRoutineReadyPriority = = 0 )
{
/* No more co-routines to check. */
return ;
}
- - uxTopCoRoutineReadyPriority ;
}
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
of the same priority get an equal share of the processor time . */
listGET_OWNER_OF_NEXT_ENTRY ( pxCurrentCoRoutine , & ( pxReadyCoRoutineLists [ uxTopCoRoutineReadyPriority ] ) ) ;
/* Call the co-routine. */
( pxCurrentCoRoutine - > pxCoRoutineFunction ) ( pxCurrentCoRoutine , pxCurrentCoRoutine - > uxIndex ) ;
return ;
}
/*-----------------------------------------------------------*/
static void prvInitialiseCoRoutineLists ( void )
{
2014-03-23 18:44:06 +01:00
UBaseType_t uxPriority ;
2013-04-05 23:59:28 +02:00
for ( uxPriority = 0 ; uxPriority < configMAX_CO_ROUTINE_PRIORITIES ; uxPriority + + )
{
2014-03-23 18:44:06 +01:00
vListInitialise ( ( List_t * ) & ( pxReadyCoRoutineLists [ uxPriority ] ) ) ;
2013-04-05 23:59:28 +02:00
}
2014-03-23 18:44:06 +01:00
vListInitialise ( ( List_t * ) & xDelayedCoRoutineList1 ) ;
vListInitialise ( ( List_t * ) & xDelayedCoRoutineList2 ) ;
vListInitialise ( ( List_t * ) & xPendingReadyCoRoutineList ) ;
2013-04-05 23:59:28 +02:00
/* Start with pxDelayedCoRoutineList using list1 and the
pxOverflowDelayedCoRoutineList using list2 . */
pxDelayedCoRoutineList = & xDelayedCoRoutineList1 ;
pxOverflowDelayedCoRoutineList = & xDelayedCoRoutineList2 ;
}
/*-----------------------------------------------------------*/
2014-03-23 18:44:06 +01:00
BaseType_t xCoRoutineRemoveFromEventList ( const List_t * pxEventList )
2013-04-05 23:59:28 +02:00
{
2014-03-23 18:44:06 +01:00
CRCB_t * pxUnblockedCRCB ;
BaseType_t xReturn ;
2013-04-05 23:59:28 +02:00
/* This function is called from within an interrupt. It can only access
event lists and the pending ready list . This function assumes that a
check has already been made to ensure pxEventList is not empty . */
2014-03-23 18:44:06 +01:00
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY ( pxEventList ) ;
2013-09-05 05:26:23 +02:00
( void ) uxListRemove ( & ( pxUnblockedCRCB - > xEventListItem ) ) ;
2014-03-23 18:44:06 +01:00
vListInsertEnd ( ( List_t * ) & ( xPendingReadyCoRoutineList ) , & ( pxUnblockedCRCB - > xEventListItem ) ) ;
2013-04-05 23:59:28 +02:00
if ( pxUnblockedCRCB - > uxPriority > = pxCurrentCoRoutine - > uxPriority )
{
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
return xReturn ;
}