mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-05-22 13:09:04 -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
|
@ -1191,6 +1191,21 @@ void vTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
|
|||
*/
|
||||
void vTaskPlaceOnEventList( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
|
||||
*
|
||||
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
|
||||
*
|
||||
* This function performs nearly the same function as vTaskPlaceOnEventList().
|
||||
* The difference being that this function does not permit tasks to block
|
||||
* indefinitely, whereas vTaskPlaceOnEventList() does.
|
||||
*
|
||||
* @return pdTRUE if the task being removed has a higher priority than the task
|
||||
* making the call, otherwise pdFALSE.
|
||||
*/
|
||||
void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
|
||||
|
|
|
@ -67,10 +67,11 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/* IDs for commands that can be sent/received on the timer queue. */
|
||||
#define tmrCOMMAND_START 0
|
||||
#define tmrCOMMAND_STOP 1
|
||||
#define tmrCOMMAND_CHANGE_PERIOD 2
|
||||
#define tmrCOMMAND_DELETE 3
|
||||
#define trmCOMMAND_PROCESS_TIMER_OVERFLOW 0 /* For use by the kernel only! */
|
||||
#define tmrCOMMAND_START 1
|
||||
#define tmrCOMMAND_STOP 2
|
||||
#define tmrCOMMAND_CHANGE_PERIOD 3
|
||||
#define tmrCOMMAND_DELETE 4
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* MACROS AND DEFINITIONS
|
||||
|
|
|
@ -1481,7 +1481,7 @@ signed portBASE_TYPE xReturn;
|
|||
if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0U )
|
||||
{
|
||||
/* There is nothing in the queue, block for the specified period. */
|
||||
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
||||
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1448,6 +1448,15 @@ void vTaskIncrementTick( void )
|
|||
pxDelayedTaskList = pxOverflowDelayedTaskList;
|
||||
pxOverflowDelayedTaskList = pxTemp;
|
||||
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 )
|
||||
{
|
||||
/* The delayed list is empty. Set xNextTaskUnblockTime to the
|
||||
|
@ -1741,6 +1750,38 @@ portTickType xTimeToWake;
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if configUSE_TIMERS == 1
|
||||
|
||||
void vTaskPlaceOnEventListRestricted( const xList * const pxEventList, portTickType xTicksToWait )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
|
||||
/* 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 for use by kernel code, and has special calling requirements -
|
||||
it should be called from a critical section. */
|
||||
|
||||
|
||||
/* Place the event list item of the TCB in the appropriate event list.
|
||||
In this case it is assume that this is the only task that is going to
|
||||
be waiting on this event list, so the faster vListInsertEnd() function
|
||||
can be used in place of vListInsert. */
|
||||
vListInsertEnd( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
|
||||
|
||||
/* 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
|
||||
function is called form a critical section. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
|
||||
|
||||
/* Calculate the time at which the task should be woken if the event does
|
||||
not occur. This may overflow but this doesn't matter. */
|
||||
xTimeToWake = xTickCount + xTicksToWait;
|
||||
prvAddCurrentTaskToDelayedList( xTimeToWake );
|
||||
}
|
||||
|
||||
#endif /* configUSE_TIMERS */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
|
||||
{
|
||||
tskTCB *pxUnblockedTCB;
|
||||
|
|
|
@ -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…
Reference in a new issue