mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-05-22 21:19:02 -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;
|
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
|
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||||
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
|
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
|
||||||
|
|
|
@ -67,10 +67,11 @@ 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 tmrCOMMAND_START 0
|
#define trmCOMMAND_PROCESS_TIMER_OVERFLOW 0 /* For use by the kernel only! */
|
||||||
#define tmrCOMMAND_STOP 1
|
#define tmrCOMMAND_START 1
|
||||||
#define tmrCOMMAND_CHANGE_PERIOD 2
|
#define tmrCOMMAND_STOP 2
|
||||||
#define tmrCOMMAND_DELETE 3
|
#define tmrCOMMAND_CHANGE_PERIOD 3
|
||||||
|
#define tmrCOMMAND_DELETE 4
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* MACROS AND DEFINITIONS
|
* MACROS AND DEFINITIONS
|
||||||
|
|
|
@ -1481,7 +1481,7 @@ signed portBASE_TYPE xReturn;
|
||||||
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. */
|
||||||
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1448,6 +1448,15 @@ void vTaskIncrementTick( void )
|
||||||
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
|
||||||
|
@ -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 )
|
signed portBASE_TYPE xTaskRemoveFromEventList( const xList * const pxEventList )
|
||||||
{
|
{
|
||||||
tskTCB *pxUnblockedTCB;
|
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.
|
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
|
/* 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
|
time order, with the nearest expiry time at the front of the list. Only the
|
||||||
timer service task is allowed to access xActiveTimerList. */
|
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. */
|
/* A queue that is used to send commands to the timer service task. */
|
||||||
PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
|
PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
|
||||||
|
@ -118,6 +124,12 @@ static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||||
*/
|
*/
|
||||||
static void prvProcessReceivedCommands( void ) 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 )
|
portBASE_TYPE xTimerCreateTimerTask( void )
|
||||||
|
@ -207,9 +219,9 @@ xTIMER *pxTimer;
|
||||||
the timer with the nearest expiry time will expire. If there are no
|
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
|
active timers then just set the next expire time to the maximum possible
|
||||||
time to ensure this task does not run unnecessarily. */
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -220,15 +232,14 @@ xTIMER *pxTimer;
|
||||||
if( xNextExpireTime <= xTaskGetTickCount() )
|
if( xNextExpireTime <= xTaskGetTickCount() )
|
||||||
{
|
{
|
||||||
/* Remove the timer from the list of active timers. */
|
/* 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 ) );
|
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||||
|
|
||||||
/* If the timer is an autoreload timer then calculate the next
|
/* If the timer is an autoreload timer then calculate the next
|
||||||
expiry time and re-insert the timer in the list of active timers. */
|
expiry time and re-insert the timer in the list of active timers. */
|
||||||
if( pxTimer->uxAutoReload == pdTRUE )
|
if( pxTimer->uxAutoReload == pdTRUE )
|
||||||
{
|
{
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );
|
prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ) );
|
||||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the timer callback. */
|
/* 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 )
|
static void prvProcessReceivedCommands( void )
|
||||||
{
|
{
|
||||||
xTIMER_MESSAGE xMessage;
|
xTIMER_MESSAGE xMessage;
|
||||||
portTickType xTimeToExpire;
|
|
||||||
xTIMER *pxTimer;
|
xTIMER *pxTimer;
|
||||||
|
xList *pxTemp;
|
||||||
|
|
||||||
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
|
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
|
||||||
{
|
{
|
||||||
pxTimer = xMessage.pxTimer;
|
pxTimer = xMessage.pxTimer;
|
||||||
|
|
||||||
/* Is the timer already in the list of active timers? */
|
/* Is the timer already in the list of active timers? When the command
|
||||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
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. */
|
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
||||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
{
|
||||||
|
/* The timer is in the list, remove it. */
|
||||||
|
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( xMessage.xMessageID )
|
switch( xMessage.xMessageID )
|
||||||
{
|
{
|
||||||
case tmrCOMMAND_START :
|
case tmrCOMMAND_START :
|
||||||
/* Start or restart a timer. */
|
/* Start or restart a timer. */
|
||||||
xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;
|
prvInsertTimerInActiveList( pxTimer, xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks );
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );
|
|
||||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
|
||||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tmrCOMMAND_STOP :
|
case tmrCOMMAND_STOP :
|
||||||
|
@ -297,10 +326,7 @@ xTIMER *pxTimer;
|
||||||
|
|
||||||
case tmrCOMMAND_CHANGE_PERIOD :
|
case tmrCOMMAND_CHANGE_PERIOD :
|
||||||
pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
|
pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
|
||||||
xTimeToExpire = xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks;
|
prvInsertTimerInActiveList( pxTimer, ( xTaskGetTickCount() + pxTimer->xTimerPeriodInTicks ) );
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xTimeToExpire );
|
|
||||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
|
||||||
vListInsert( &xActiveTimerList, &( pxTimer->xTimerListItem ) );
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tmrCOMMAND_DELETE :
|
case tmrCOMMAND_DELETE :
|
||||||
|
@ -309,6 +335,14 @@ xTIMER *pxTimer;
|
||||||
vPortFree( pxTimer );
|
vPortFree( pxTimer );
|
||||||
break;
|
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 :
|
default :
|
||||||
/* Don't expect to get here. */
|
/* Don't expect to get here. */
|
||||||
break;
|
break;
|
||||||
|
@ -326,7 +360,10 @@ static void prvCheckForValidListAndQueue( void )
|
||||||
{
|
{
|
||||||
if( xTimerQueue == NULL )
|
if( xTimerQueue == NULL )
|
||||||
{
|
{
|
||||||
vListInitialise( &xActiveTimerList );
|
vListInitialise( &xActiveTimerList1 );
|
||||||
|
vListInitialise( &xActiveTimerList2 );
|
||||||
|
pxCurrentTimerList = &xActiveTimerList1;
|
||||||
|
pxOverflowTimerList = &xActiveTimerList2;
|
||||||
xTimerQueue = xQueueCreate( configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
|
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? */
|
/* Is the timer in the list of active timers? */
|
||||||
taskENTER_CRITICAL();
|
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();
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue