mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-08-19 17:48:33 -04:00
Add some tick interrupt overflow protection to the timers module. This is not tested yet and still a work in progress.
This commit is contained in:
parent
671ca2724e
commit
7ee534e4c2
5 changed files with 124 additions and 27 deletions
|
@ -1,4 +1,7 @@
|
|||
/* Need a method of switching to an overflow list. _RB_*/
|
||||
/* Need to consider the switching of timer lists, and the placement of tasks into
|
||||
the current and overflow timer lists very carefully. For example, should the
|
||||
assessment as to which list a timer should be inserted into be relative the the
|
||||
tick count at the timer, or the tick count when the timer task unblocked, etc. */
|
||||
|
||||
/*
|
||||
FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
@ -92,7 +95,10 @@ typedef struct tmrTimerQueueMessage
|
|||
/* The list in which active timers are stored. Timers are referenced in expire
|
||||
time order, with the nearest expiry time at the front of the list. Only the
|
||||
timer service task is allowed to access xActiveTimerList. */
|
||||
PRIVILEGED_DATA static xList xActiveTimerList;
|
||||
PRIVILEGED_DATA static xList xActiveTimerList1;
|
||||
PRIVILEGED_DATA static xList xActiveTimerList2;
|
||||
PRIVILEGED_DATA static xList *pxCurrentTimerList;
|
||||
PRIVILEGED_DATA static xList *pxOverflowTimerList;
|
||||
|
||||
/* A queue that is used to send commands to the timer service task. */
|
||||
PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
|
||||
|
@ -118,6 +124,12 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
|||
*/
|
||||
static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
|
||||
* depending on if the expire time causes a timer counter overflow.
|
||||
*/
|
||||
static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xTimerCreateTimerTask( void )
|
||||
|
@ -207,9 +219,9 @@ xTIMER *pxTimer;
|
|||
the timer with the nearest expiry time will expire. If there are no
|
||||
active timers then just set the next expire time to the maximum possible
|
||||
time to ensure this task does not run unnecessarily. */
|
||||
if( listLIST_IS_EMPTY( &xActiveTimerList ) == pdFALSE )
|
||||
if( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
|
||||
{
|
||||
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( &xActiveTimerList );
|
||||
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -220,15 +232,14 @@ xTIMER *pxTimer;
|
|||
if( xNextExpireTime <= xTaskGetTickCount() )
|
||||
{
|
||||
/* Remove the timer from the list of active timers. */
|
||||
pxTimer = listGET_OWNER_OF_HEAD_ENTRY( &xActiveTimerList );
|
||||
pxTimer = listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
|
||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||
|
||||
/* If the timer is an autoreload timer then calculate the next
|
||||
expiry time and re-insert the timer in the list of active timers. */
|
||||
if( pxTimer->uxAutoReload == pdTRUE )
|
||||
{
|
||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );
|
||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
||||
prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );
|
||||
}
|
||||
|
||||
/* Call the timer callback. */
|
||||
|
@ -263,31 +274,49 @@ xTIMER *pxTimer;
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime )
|
||||
{
|
||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
||||
|
||||
if( xNextExpiryTime < xTaskGetTickCount() )
|
||||
{
|
||||
vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvProcessReceivedCommands( void )
|
||||
{
|
||||
xTIMER_MESSAGE xMessage;
|
||||
portTickType xTimeToExpire;
|
||||
xTIMER *pxTimer;
|
||||
xList *pxTemp;
|
||||
|
||||
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
|
||||
{
|
||||
pxTimer = xMessage.pxTimer;
|
||||
|
||||
/* Is the timer already in the list of active timers? */
|
||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
||||
/* Is the timer already in the list of active timers? When the command
|
||||
is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the
|
||||
command is to the task rather than to an individual timer. */
|
||||
if( pxTimer != NULL )
|
||||
{
|
||||
/* The timer is in the list, remove it. */
|
||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
||||
{
|
||||
/* The timer is in the list, remove it. */
|
||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
}
|
||||
|
||||
switch( xMessage.xMessageID )
|
||||
{
|
||||
case tmrCOMMAND_START :
|
||||
/* Start or restart a timer. */
|
||||
xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;
|
||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
||||
prvInsertTimerInActiveList( pxTimer, xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks );
|
||||
break;
|
||||
|
||||
case tmrCOMMAND_STOP :
|
||||
|
@ -297,10 +326,7 @@ xTIMER *pxTimer;
|
|||
|
||||
case tmrCOMMAND_CHANGE_PERIOD :
|
||||
pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
|
||||
xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;
|
||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
||||
prvInsertTimerInActiveList( pxTimer, ( xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks ) );
|
||||
break;
|
||||
|
||||
case tmrCOMMAND_DELETE :
|
||||
|
@ -308,6 +334,14 @@ xTIMER *pxTimer;
|
|||
just free up the memory. */
|
||||
vPortFree( pxTimer );
|
||||
break;
|
||||
|
||||
case trmCOMMAND_PROCESS_TIMER_OVERFLOW :
|
||||
/* The tick count has overflowed. The timer lists must be
|
||||
switched. */
|
||||
pxTemp = pxCurrentTimerList;
|
||||
pxCurrentTimerList = pxOverflowTimerList;
|
||||
pxOverflowTimerList = pxTemp;
|
||||
break;
|
||||
|
||||
default :
|
||||
/* Don't expect to get here. */
|
||||
|
@ -326,7 +360,10 @@ static void prvCheckForValidListAndQueue( void )
|
|||
{
|
||||
if( xTimerQueue == NULL )
|
||||
{
|
||||
vListInitialise( &xActiveTimerList );
|
||||
vListInitialise( &xActiveTimerList1 );
|
||||
vListInitialise( &xActiveTimerList2 );
|
||||
pxCurrentTimerList = &xActiveTimerList1;
|
||||
pxOverflowTimerList = &xActiveTimerList2;
|
||||
xTimerQueue = xQueueCreate( configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +379,10 @@ xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
|||
/* Is the timer in the list of active timers? */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
xTimerIsInActiveList = listIS_CONTAINED_WITHIN( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
||||
/* Checking to see if it is in the NULL list in effect checks to see if
|
||||
it is referenced from either the current or the overflow timer lists in
|
||||
one go, but the logic has to be reversed, hence the '!'. */
|
||||
xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue