Continue work on the new timer implementation. Nearly complete.

This commit is contained in:
Richard Barry 2011-02-14 10:51:18 +00:00
parent 07a2021676
commit b4ff4820cb
5 changed files with 211 additions and 155 deletions

View File

@ -181,6 +181,10 @@ typedef portBASE_TYPE (*pdTASK_HOOK_CODE)( void * );
#define INCLUDE_xTaskResumeFromISR 1 #define INCLUDE_xTaskResumeFromISR 1
#endif #endif
#ifndef configASSERT
#define configASSERT( x )
#endif
/* The timers module relies on xTaskGetSchedulerState(). */ /* The timers module relies on xTaskGetSchedulerState(). */
#if configUSE_TIMERS == 1 #if configUSE_TIMERS == 1

View File

@ -67,11 +67,10 @@ extern "C" {
#endif #endif
/* IDs for commands that can be sent/received on the timer queue. */ /* IDs for commands that can be sent/received on the timer queue. */
#define trmCOMMAND_PROCESS_TIMER_OVERFLOW 0 /* For use by the kernel only! */ #define tmrCOMMAND_START 0
#define tmrCOMMAND_START 1 #define tmrCOMMAND_STOP 1
#define tmrCOMMAND_STOP 2 #define tmrCOMMAND_CHANGE_PERIOD 2
#define tmrCOMMAND_CHANGE_PERIOD 3 #define tmrCOMMAND_DELETE 3
#define tmrCOMMAND_DELETE 4
/*----------------------------------------------------------- /*-----------------------------------------------------------
* MACROS AND DEFINITIONS * MACROS AND DEFINITIONS

View File

@ -1469,20 +1469,27 @@ signed portBASE_TYPE xReturn;
void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait ) void vQueueWaitForMessageRestricted( xQueueHandle pxQueue, portTickType xTicksToWait )
{ {
/* This function should not be called by application code hence the /* This function should not be called by application code hence the
'Restricted' in its name. It is not part of the public API. It is designed 'Restricted' in its name. It is not part of the public API. It is
for use by kernel code, and has special calling requirements - it should be designed for use by kernel code, and has special calling requirements.
called from a critical section, and then a yield performed after it is It can result in vListInsert() being called on a list that can only
called. Also, the call tree makes use of vListInsert() which should normally possibly ever have one item in it, so the list will be fast, but even
not be called from a critical section - so an assumption is made that the list so it should be called with the scheduler locked and not from a critical
being inserted into is empty and therefore the insertion will be fast. */ section. */
/* Only do anything if there are no message in the queue. */ /* Only do anything if there are no messages in the queue. This function
will not actually cause the task to block, just place it on a blocked
list. It will not block until the scheduler is unlocked - at which
time a yield will be performed. If an item is added to the queue while
the queue is locked, and the calling task blocks on the queue, then the
calling task will be immediately unblocked when the queue is unlocked. */
prvLockQueue( pxQueue );
if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U ) if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )
{ {
/* There is nothing in the queue, block for the specified period. */ /* There is nothing in the queue, block for the specified period. */
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
} }
prvUnlockQueue( pxQueue );
} }
#endif #endif

View File

@ -754,7 +754,7 @@ tskTCB *pxTCB = ( tskTCB * ) pxTask;
/* This function is not intended to be a public API function and definitely /* This function is not intended to be a public API function and definitely
is not for generic use as it assumes pxTask is not the running task and not is not for generic use as it assumes pxTask is not the running task and not
suspended, does not remove the task from any event lists it might be suspended, does not remove the task from any event lists it might be
blocked on, and does not take care of mutual exclusion. */ blocked on, and does not take care of mutual exclusion. */
vListRemove( &( pxTCB->xGenericListItem ) ); vListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB ); prvAddTaskToReadyQueue( pxTCB );
@ -1444,19 +1444,13 @@ void vTaskIncrementTick( void )
/* Tick count has overflowed so we need to swap the delay lists. /* Tick count has overflowed so we need to swap the delay lists.
If there are any items in pxDelayedTaskList here then there is If there are any items in pxDelayedTaskList here then there is
an error! */ an error! */
configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );
pxTemp = pxDelayedTaskList; pxTemp = pxDelayedTaskList;
pxDelayedTaskList = pxOverflowDelayedTaskList; pxDelayedTaskList = pxOverflowDelayedTaskList;
pxOverflowDelayedTaskList = pxTemp; pxOverflowDelayedTaskList = pxTemp;
xNumOfOverflows++; xNumOfOverflows++;
#if configUSE_TIMERS == 1
{
/* The timer service task needs to know to switch its lists
too. */
xTimerGenericCommand( NULL, trmCOMMAND_PROCESS_TIMER_OVERFLOW, 0, 0 );
}
#endif
if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE )
{ {
/* The delayed list is empty. Set xNextTaskUnblockTime to the /* The delayed list is empty. Set xNextTaskUnblockTime to the
@ -1756,9 +1750,9 @@ portTickType xTimeToWake;
{ {
portTickType xTimeToWake; portTickType xTimeToWake;
/* This function should not be called by application code hence the /* This function should not be called by application code hence the
'Restricted' in its name. It is not part of the public API. It is 'Restricted' in its name. It is not part of the public API. It is
designed for use by kernel code, and has special calling requirements - designed for use by kernel code, and has special calling requirements -
it should be called from a critical section. */ it should be called from a critical section. */
@ -1769,7 +1763,7 @@ portTickType xTimeToWake;
vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) ); vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
/* We must remove this task from the ready list before adding it to the /* We must remove this task from the ready list before adding it to the
blocked list as the same list item is used for both lists. This blocked list as the same list item is used for both lists. This
function is called form a critical section. */ function is called form a critical section. */
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) ); vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );

View File

@ -117,25 +117,45 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
* Called by the timer service task to interpret and process a command it * Called by the timer service task to interpret and process a command it
* received on the timer queue. * received on the timer queue.
*/ */
static void prvProcessReceivedCommands( portTickType xAssumedTimeNow ) PRIVILEGED_FUNCTION; static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
/* /*
* Insert the timer into either xActiveTimerList1, or xActiveTimerList2, * Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
* depending on if the expire time causes a timer counter overflow. * depending on if the expire time causes a timer counter overflow.
*/ */
static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xAssumedTimeNow ) PRIVILEGED_FUNCTION; static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
/* /*
* An active timer has reached its expire time. Reload the timer if it is an * An active timer has reached its expire time. Reload the timer if it is an
* auto reload timer, then call its callback. * auto reload timer, then call its callback.
*/ */
static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xAssumedTimeNow ) PRIVILEGED_FUNCTION; static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
/* /*
* The tick count has overflowed. Switch the timer lists after ensuring the * The tick count has overflowed. Switch the timer lists after ensuring the
* current timer list does not still reference some timers. * current timer list does not still reference some timers.
*/ */
static void prvSwitchTimerLists( portTickType xAssumedTimeNow ) PRIVILEGED_FUNCTION; static void prvSwitchTimerLists( portTickType xTimeNow, portTickType xLastTime ) PRIVILEGED_FUNCTION;
/*
* Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
* if a tick count overflow occurred since prvSampleTimeNow() was last called.
*/
static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
/*
* If the timer list contains any active timers then return the expire time of
* the timer that will expire first and set *pxListWasEmpty to false. If the
* timer list does not contain any timers then return 0 and set *pxListWasEmpty
* to pdTRUE.
*/
static portTickType prvLookForExpiredTimer( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
/*
* If a timer has expired, process it. Otherwise, block the timer service task
* until either a timer does expire or a command is received.
*/
static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -151,7 +171,7 @@ portBASE_TYPE xReturn = pdFAIL;
if( xTimerQueue != NULL ) if( xTimerQueue != NULL )
{ {
xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Timer Service", configTIMER_TASK_STACK_DEPTH, NULL, configTIMER_TASK_PRIORITY, NULL ); xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", configTIMER_TASK_STACK_DEPTH, NULL, configTIMER_TASK_PRIORITY, NULL);
} }
return xReturn; return xReturn;
@ -183,7 +203,7 @@ xTIMER *pxNewTimer;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portTickType xBlockTime ) portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
{ {
portBASE_TYPE xReturn = pdFAIL; portBASE_TYPE xReturn = pdFAIL;
xTIMER_MESSAGE xMessage; xTIMER_MESSAGE xMessage;
@ -197,13 +217,20 @@ xTIMER_MESSAGE xMessage;
xMessage.xMessageValue = xOptionalValue; xMessage.xMessageValue = xOptionalValue;
xMessage.pxTimer = ( xTIMER * ) xTimer; xMessage.pxTimer = ( xTIMER * ) xTimer;
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) if( pxHigherPriorityTaskWoken == NULL )
{ {
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime ); if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
{
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
}
else
{
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
}
} }
else else
{ {
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY ); xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
} }
} }
@ -211,128 +238,155 @@ xTIMER_MESSAGE xMessage;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xAssumedTimeNow ) static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
{ {
xTIMER *pxTimer; xTIMER *pxTimer;
if( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) /* Remove the timer from the list of active timers. A check has already
been performed to ensure the list is not empty. */
pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
vListRemove( &( pxTimer->xTimerListItem ) );
/* If the timer is an auto reload timer then calculate the next
expiry time and re-insert the timer in the list of active timers. */
if( pxTimer->uxAutoReload == pdTRUE )
{ {
/* Remove the timer from the list of active timers. */ /* This is the only time a timer is inserted into a list using
pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); a time relative to anything other than the current time. It
vListRemove( &( pxTimer->xTimerListItem ) ); will therefore be inserted into the correct list relative to
the time this task thinks it is now, even if a command to
/* If the timer is an auto reload timer then calculate the next switch lists due to a tick count overflow is already waiting in
expiry time and re-insert the timer in the list of active timers. */ the timer queue. */
if( pxTimer->uxAutoReload == pdTRUE ) prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow );
{
/* This is the only time a timer is inserted into a list using
a time relative to anything other than the current time. It
will therefore be inserted into the correct list relative to
the time this task thinks it is now, even if a command to
switch lists due to a tick count overflow is already waiting in
the timer queue. */
prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xAssumedTimeNow );
}
/* Call the timer callback. */
pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
} }
/* Call the timer callback. */
pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvTimerTask( void *pvParameters ) static void prvTimerTask( void *pvParameters )
{ {
portTickType xNextExpireTime, xTimeNow, xFrozenTimeNow; portTickType xNextExpireTime;
portBASE_TYPE xListWasEmpty;
/* Just to avoid compiler warnings. */ /* Just to avoid compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
for( ;; ) for( ;; )
{ {
/* Take a snapshot of the time to use while assessing expiry and auto /* Query the timers list to see if it contains any timers, and if so,
reload times. */ obtain the time at which the next timer will expire. */
xFrozenTimeNow = xTaskGetTickCount(); xNextExpireTime = prvLookForExpiredTimer( &xListWasEmpty );
/* Timers are listed in expiry time order, with the head of the list /* If a timer has expired, process it. Otherwise, block this task
referencing the task that will expire first. Obtain the time at which until either a timer does expire, or a command is received. */
the timer with the nearest expiry time will expire. If there are no prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
active timers then just set the next expire time to the maximum possible
time to ensure this task does not run unnecessarily. */ /* Empty the command queue. */
if( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) prvProcessReceivedCommands();
{
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
}
else
{
xNextExpireTime = portMAX_DELAY;
}
/* Has the timer expired? This expiry time is relative to the snapshot
of the time taken to be used in this loop iteration - so it doesn't
matter at this point if a tick count overflows here. */
if( xNextExpireTime <= xFrozenTimeNow )
{
prvProcessExpiredTimer( xNextExpireTime, xFrozenTimeNow );
}
else
{
/* Block this task until the next timer expires, or a command is
received. */
vTaskSuspendAll();
{
/* Has the tick overflowed since a time snapshot was taken? */
xTimeNow = xTaskGetTickCount();
if( xTimeNow >= xFrozenTimeNow )
{
/* Has the expire not still not been met? The tick count
may be greater now than when the time snapshot was taken. */
if( xNextExpireTime <= xTimeNow )
{
prvProcessExpiredTimer( xNextExpireTime, xFrozenTimeNow );
}
else
{
/* The tick count has not overflowed since the time
snapshot, and the next expire time has not been reached
since the last snapshot was taken. This task should
therefore block to wait for the next expire time. */
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
}
}
else
{
/* The tick count has overflowed since the time snapshot
was taken, therefore, the task should not block but continue
with another loop. The command queue should contain a
command to switch lists. */
}
}
if( xTaskResumeAll() == pdFALSE )
{
/* Yield to wait for either a command to arrive, or the block time
to expire. If a command arrived between the critical section being
exited and this yield then the yield will just return to the same
task. */
portYIELD_WITHIN_API();
}
/* Take a snapshot of the time now for use in this iteration of the
task loop. */
xFrozenTimeNow = xTaskGetTickCount();
/* Empty the command queue, if it contains any commands. */
prvProcessReceivedCommands( xFrozenTimeNow );
}
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xAssumedTimeNow ) static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
{
portTickType xTimeNow;
portBASE_TYPE xTimerListsWereSwitched;
vTaskSuspendAll();
{
/* Obtain the time now to make an assessment as to whether the timer
has expired or not. If obtaining the time causes the lists to switch
then don't process this timer as any timers that remained in the list
when the lists were switched will have been processed within the
prvSampelTimeNow() function. */
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
if( xTimerListsWereSwitched == pdFALSE )
{
/* The tick count has not overflowed, has the timer expired? */
if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
{
prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
}
else
{
/* The tick count has not overflowed, and the next expire
time has not been reached yet. This task should therefore
block to wait for the next expire time or a command to be
received - whichever comes first. The following line cannot
be reached unless xNextExpireTime > xTimeNow, except in the
case when the current timer list is empty. */
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
}
}
}
if( xTaskResumeAll() == pdFALSE )
{
/* Yield to wait for either a command to arrive, or the block time
to expire. If a command arrived between the critical section being
exited and this yield then the yield will not cause the task
to block. */
portYIELD_WITHIN_API();
}
}
/*-----------------------------------------------------------*/
static portTickType prvLookForExpiredTimer( portBASE_TYPE *pxListWasEmpty )
{
portTickType xNextExpireTime;
/* Timers are listed in expiry time order, with the head of the list
referencing the task that will expire first. Obtain the time at which
the timer with the nearest expiry time will expire. If there are no
active timers then just set the next expire time to 0. That will cause
this task to unblock when the tick count overflows, at which point the
timer lists will be switched and the next expiry time can be
re-assessed. */
*pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
if( *pxListWasEmpty == pdFALSE )
{
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
}
else
{
/* Ensure the task unblocks when the tick count rolls over. */
xNextExpireTime = ( portTickType ) 0U;
}
return xNextExpireTime;
}
/*-----------------------------------------------------------*/
static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
{
portTickType xTimeNow;
static portTickType xLastTime = ( portTickType ) 0U;
xTimeNow = xTaskGetTickCount();
if( xTimeNow < xLastTime )
{
prvSwitchTimerLists( xTimeNow, xLastTime );
*pxTimerListsWereSwitched = pdTRUE;
}
else
{
*pxTimerListsWereSwitched = pdFALSE;
}
xLastTime = xTimeNow;
return xTimeNow;
}
/*-----------------------------------------------------------*/
static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow )
{ {
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime ); listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer ); listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
if( xNextExpiryTime < xAssumedTimeNow ) if( xNextExpiryTime < xTimeNow )
{ {
vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) ); vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
} }
@ -343,11 +397,16 @@ static void prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpir
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvProcessReceivedCommands( portTickType xAssumedTimeNow ) static void prvProcessReceivedCommands( void )
{ {
xTIMER_MESSAGE xMessage; xTIMER_MESSAGE xMessage;
xTIMER *pxTimer; xTIMER *pxTimer;
portBASE_TYPE xSwitchListsOnExit = pdFALSE; portBASE_TYPE xTimerListsWereSwitched;
portTickType xTimeNow;
/* In this case the xTimerListsWereSwitched parameter is not used, but it
must be present in the function call. */
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
{ {
@ -369,7 +428,7 @@ portBASE_TYPE xSwitchListsOnExit = pdFALSE;
{ {
case tmrCOMMAND_START : case tmrCOMMAND_START :
/* Start or restart a timer. */ /* Start or restart a timer. */
prvInsertTimerInActiveList( pxTimer, xAssumedTimeNow + pxTimer->xTimerPeriodInTicks, xAssumedTimeNow ); prvInsertTimerInActiveList( pxTimer, xTimeNow + pxTimer->xTimerPeriodInTicks, xTimeNow );
break; break;
case tmrCOMMAND_STOP : case tmrCOMMAND_STOP :
@ -379,7 +438,7 @@ portBASE_TYPE xSwitchListsOnExit = pdFALSE;
case tmrCOMMAND_CHANGE_PERIOD : case tmrCOMMAND_CHANGE_PERIOD :
pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue; pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
prvInsertTimerInActiveList( pxTimer, ( xAssumedTimeNow + pxTimer->xTimerPeriodInTicks ), xAssumedTimeNow ); prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow );
break; break;
case tmrCOMMAND_DELETE : case tmrCOMMAND_DELETE :
@ -387,39 +446,32 @@ portBASE_TYPE xSwitchListsOnExit = pdFALSE;
just free up the memory. */ just free up the memory. */
vPortFree( pxTimer ); vPortFree( pxTimer );
break; break;
case trmCOMMAND_PROCESS_TIMER_OVERFLOW :
/* Hold this pending until all the other messages have been
processed. */
xSwitchListsOnExit = pdTRUE;
break;
default : default :
/* Don't expect to get here. */ /* Don't expect to get here. */
break; break;
} }
} }
if( xSwitchListsOnExit == pdTRUE )
{
prvSwitchTimerLists( xAssumedTimeNow );
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvSwitchTimerLists( portTickType xAssumedTimeNow ) static void prvSwitchTimerLists( portTickType xTimeNow, portTickType xLastTime )
{ {
portTickType xNextExpireTime; portTickType xNextExpireTime;
xList *pxTemp; xList *pxTemp;
/* The tick count has overflowed. The timer lists must be switched. /* Remove compiler warnings if configASSERT() is not defined. */
If there are any timers still referenced from the current timer list ( void ) xLastTime;
then they must have expired and should be processed before the lists
/* The tick count has overflowed. The timer lists must be switched.
If there are any timers still referenced from the current timer list
then they must have expired and should be processed before the lists
are switched. */ are switched. */
while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE ) while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
{ {
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
prvProcessExpiredTimer( xNextExpireTime, xAssumedTimeNow ); configASSERT( ( xNextExpireTime >= xLastTime ) );
prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
} }
pxTemp = pxCurrentTimerList; pxTemp = pxCurrentTimerList;