Remove support for tmrCOMMAND_START_DONT_TRACE (#305)
* Remove support for tmrCOMMAND_START_DONT_TRACE
Prior to this commit, the timer task used tmrCOMMAND_START_DONT_TRACE
to reload a "backlogged" auto-reload timer -- one for which a reload
operation would have started a period that had already elapsed. If the
command queue contained a stop or delete command when
tmrCOMMAND_START_DONT_TRACE was put into the queue for a reload, the
timer unexpectedly restarted when the timer task processed
tmrCOMMAND_START_DONT_TRACE. This commit implements a new method of
reloading auto-reload timers and eliminates support for
tmrCOMMAND_START_DONT_TRACE. No other code sends this private command.
However, the symbol tmrCOMMAND_START_DONT_TRACE remains defined, with
its original command value, so as not to impact trace applications.
Also fix one-shot timers that were not reliably being marked as not
active:
- when they expired before the start command could be processed
- when the expiration was processed during the timer list switch
Also improve consistency:
- Always reload auto-reload timers *before* calling the callback.
- Always call traceTIMER_EXPIRED() just prior to the callback.
* fix indent
* Revert unnecessary change to prvTimerTask()
Change was intended to faithfully work through a backlog that spanned a
list switch, and before processing a stop or delete command. But, (1)
it isn't important to do that, and (2) the code didn't accomplish the
intention when *two* auto-reload timers were backlogged across a list
switch. Best to simply leave this part of the code as it was before.
* fix style
Co-authored-by: Joseph Julicher <jjulicher@mac.com>
diff --git a/timers.c b/timers.c
index 203a077..8032a1f 100644
--- a/timers.c
+++ b/timers.c
@@ -55,7 +55,8 @@
#if ( configUSE_TIMERS == 1 )
/* Misc definitions. */
- #define tmrNO_DELAY ( TickType_t ) 0U
+ #define tmrNO_DELAY ( ( TickType_t ) 0U )
+ #define tmrMAX_TIME_BEFORE_OVERFLOW ( ( TickType_t ) -1 )
/* The name assigned to the timer service task. This can be overridden by
* defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
@@ -173,6 +174,15 @@
const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
/*
+ * Reload the specified auto-reload timer. If the reloading is backlogged,
+ * clear the backlog, calling the callback for each additional reload. When
+ * this function returns, the next expiry time is after xTimeNow.
+ */
+ static void prvReloadTimer( Timer_t * const pxTimer,
+ TickType_t xExpiredTime,
+ const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
+
+/*
* An active timer has reached its expire time. Reload the timer if it is an
* auto-reload timer, then call its callback.
*/
@@ -502,45 +512,47 @@
}
/*-----------------------------------------------------------*/
+ static void prvReloadTimer( Timer_t * const pxTimer,
+ TickType_t xExpiredTime,
+ const TickType_t xTimeNow )
+ {
+ /* Insert the timer into the appropriate list for the next expiry time.
+ * If the next expiry time has already passed, advance the expiry time,
+ * call the callback function, and try again. */
+ while ( prvInsertTimerInActiveList( pxTimer, ( xExpiredTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xExpiredTime ) != pdFALSE )
+ {
+ /* Advance the expiry time. */
+ xExpiredTime += pxTimer->xTimerPeriodInTicks;
+
+ /* Call the timer callback. */
+ traceTIMER_EXPIRED( pxTimer );
+ pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
+ }
+ }
+/*-----------------------------------------------------------*/
+
static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
const TickType_t xTimeNow )
{
- BaseType_t xResult;
Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
/* Remove the timer from the list of active timers. A check has already
* been performed to ensure the list is not empty. */
-
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
- traceTIMER_EXPIRED( pxTimer );
/* 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->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
{
- /* The 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. */
- if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )
- {
- /* The timer expired before it was added to the active timer
- * list. Reload it now. */
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
- configASSERT( xResult );
- ( void ) xResult;
- }
- else
- {
- mtCOVERAGE_TEST_MARKER();
- }
+ prvReloadTimer( pxTimer, xNextExpireTime, xTimeNow );
}
else
{
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
- mtCOVERAGE_TEST_MARKER();
}
/* Call the timer callback. */
+ traceTIMER_EXPIRED( pxTimer );
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
}
/*-----------------------------------------------------------*/
@@ -741,7 +753,7 @@
{
DaemonTaskMessage_t xMessage;
Timer_t * pxTimer;
- BaseType_t xTimerListsWereSwitched, xResult;
+ BaseType_t xTimerListsWereSwitched;
TickType_t xTimeNow;
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */
@@ -802,7 +814,6 @@
case tmrCOMMAND_START_FROM_ISR:
case tmrCOMMAND_RESET:
case tmrCOMMAND_RESET_FROM_ISR:
- case tmrCOMMAND_START_DONT_TRACE:
/* Start or restart a timer. */
pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
@@ -810,19 +821,18 @@
{
/* The timer expired before it was added to the active
* timer list. Process it now. */
- pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
- traceTIMER_EXPIRED( pxTimer );
-
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
{
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
- configASSERT( xResult );
- ( void ) xResult;
+ prvReloadTimer( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow );
}
else
{
- mtCOVERAGE_TEST_MARKER();
+ pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
}
+
+ /* Call the timer callback. */
+ traceTIMER_EXPIRED( pxTimer );
+ pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
}
else
{
@@ -889,10 +899,8 @@
static void prvSwitchTimerLists( void )
{
- TickType_t xNextExpireTime, xReloadTime;
+ TickType_t xNextExpireTime;
List_t * pxTemp;
- Timer_t * pxTimer;
- BaseType_t xResult;
/* The tick count has overflowed. The timer lists must be switched.
* If there are any timers still referenced from the current timer list
@@ -902,43 +910,10 @@
{
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
- /* Remove the timer from the list. */
- pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); /*lint !e9087 !e9079 void * is used as this macro is used with tasks and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
- ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
- traceTIMER_EXPIRED( pxTimer );
-
- /* Execute its callback, then send a command to restart the timer if
- * it is an auto-reload timer. It cannot be restarted here as the lists
- * have not yet been switched. */
- pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
-
- if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
- {
- /* Calculate the reload value, and if the reload value results in
- * the timer going into the same timer list then it has already expired
- * and the timer should be re-inserted into the current list so it is
- * processed again within this loop. Otherwise a command should be sent
- * to restart the timer to ensure it is only inserted into a list after
- * the lists have been swapped. */
- xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
-
- if( xReloadTime > xNextExpireTime )
- {
- listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
- listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
- vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
- }
- else
- {
- xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
- configASSERT( xResult );
- ( void ) xResult;
- }
- }
- else
- {
- mtCOVERAGE_TEST_MARKER();
- }
+ /* Process the expired timer. For auto-reload timers, be careful to
+ * process only expirations that occur on the current list. Further
+ * expirations must wait until after the lists are switched. */
+ prvProcessExpiredTimer( xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW );
}
pxTemp = pxCurrentTimerList;