Skip to content

Commit 05ded5b

Browse files
jefftenneyn9wxu
andauthored
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>
1 parent a22b438 commit 05ded5b

File tree

1 file changed

+44
-69
lines changed

1 file changed

+44
-69
lines changed

timers.c

Lines changed: 44 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
#if ( configUSE_TIMERS == 1 )
5656

5757
/* Misc definitions. */
58-
#define tmrNO_DELAY ( TickType_t ) 0U
58+
#define tmrNO_DELAY ( ( TickType_t ) 0U )
59+
#define tmrMAX_TIME_BEFORE_OVERFLOW ( ( TickType_t ) -1 )
5960

6061
/* The name assigned to the timer service task. This can be overridden by
6162
* defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
@@ -172,6 +173,15 @@
172173
const TickType_t xTimeNow,
173174
const TickType_t xCommandTime ) PRIVILEGED_FUNCTION;
174175

176+
/*
177+
* Reload the specified auto-reload timer. If the reloading is backlogged,
178+
* clear the backlog, calling the callback for each additional reload. When
179+
* this function returns, the next expiry time is after xTimeNow.
180+
*/
181+
static void prvReloadTimer( Timer_t * const pxTimer,
182+
TickType_t xExpiredTime,
183+
const TickType_t xTimeNow ) PRIVILEGED_FUNCTION;
184+
175185
/*
176186
* An active timer has reached its expire time. Reload the timer if it is an
177187
* auto-reload timer, then call its callback.
@@ -502,45 +512,47 @@
502512
}
503513
/*-----------------------------------------------------------*/
504514

515+
static void prvReloadTimer( Timer_t * const pxTimer,
516+
TickType_t xExpiredTime,
517+
const TickType_t xTimeNow )
518+
{
519+
/* Insert the timer into the appropriate list for the next expiry time.
520+
* If the next expiry time has already passed, advance the expiry time,
521+
* call the callback function, and try again. */
522+
while ( prvInsertTimerInActiveList( pxTimer, ( xExpiredTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xExpiredTime ) != pdFALSE )
523+
{
524+
/* Advance the expiry time. */
525+
xExpiredTime += pxTimer->xTimerPeriodInTicks;
526+
527+
/* Call the timer callback. */
528+
traceTIMER_EXPIRED( pxTimer );
529+
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
530+
}
531+
}
532+
/*-----------------------------------------------------------*/
533+
505534
static void prvProcessExpiredTimer( const TickType_t xNextExpireTime,
506535
const TickType_t xTimeNow )
507536
{
508-
BaseType_t xResult;
509537
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. */
510538

511539
/* Remove the timer from the list of active timers. A check has already
512540
* been performed to ensure the list is not empty. */
513-
514541
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
515-
traceTIMER_EXPIRED( pxTimer );
516542

517543
/* If the timer is an auto-reload timer then calculate the next
518544
* expiry time and re-insert the timer in the list of active timers. */
519545
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
520546
{
521-
/* The timer is inserted into a list using a time relative to anything
522-
* other than the current time. It will therefore be inserted into the
523-
* correct list relative to the time this task thinks it is now. */
524-
if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )
525-
{
526-
/* The timer expired before it was added to the active timer
527-
* list. Reload it now. */
528-
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
529-
configASSERT( xResult );
530-
( void ) xResult;
531-
}
532-
else
533-
{
534-
mtCOVERAGE_TEST_MARKER();
535-
}
547+
prvReloadTimer( pxTimer, xNextExpireTime, xTimeNow );
536548
}
537549
else
538550
{
539551
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
540-
mtCOVERAGE_TEST_MARKER();
541552
}
542553

543554
/* Call the timer callback. */
555+
traceTIMER_EXPIRED( pxTimer );
544556
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
545557
}
546558
/*-----------------------------------------------------------*/
@@ -741,7 +753,7 @@
741753
{
742754
DaemonTaskMessage_t xMessage;
743755
Timer_t * pxTimer;
744-
BaseType_t xTimerListsWereSwitched, xResult;
756+
BaseType_t xTimerListsWereSwitched;
745757
TickType_t xTimeNow;
746758

747759
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,27 +814,25 @@
802814
case tmrCOMMAND_START_FROM_ISR:
803815
case tmrCOMMAND_RESET:
804816
case tmrCOMMAND_RESET_FROM_ISR:
805-
case tmrCOMMAND_START_DONT_TRACE:
806817
/* Start or restart a timer. */
807818
pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE;
808819

809820
if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE )
810821
{
811822
/* The timer expired before it was added to the active
812823
* timer list. Process it now. */
813-
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
814-
traceTIMER_EXPIRED( pxTimer );
815-
816824
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
817825
{
818-
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
819-
configASSERT( xResult );
820-
( void ) xResult;
826+
prvReloadTimer( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow );
821827
}
822828
else
823829
{
824-
mtCOVERAGE_TEST_MARKER();
830+
pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE;
825831
}
832+
833+
/* Call the timer callback. */
834+
traceTIMER_EXPIRED( pxTimer );
835+
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
826836
}
827837
else
828838
{
@@ -889,10 +899,8 @@
889899

890900
static void prvSwitchTimerLists( void )
891901
{
892-
TickType_t xNextExpireTime, xReloadTime;
902+
TickType_t xNextExpireTime;
893903
List_t * pxTemp;
894-
Timer_t * pxTimer;
895-
BaseType_t xResult;
896904

897905
/* The tick count has overflowed. The timer lists must be switched.
898906
* If there are any timers still referenced from the current timer list
@@ -902,43 +910,10 @@
902910
{
903911
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
904912

905-
/* Remove the timer from the list. */
906-
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. */
907-
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
908-
traceTIMER_EXPIRED( pxTimer );
909-
910-
/* Execute its callback, then send a command to restart the timer if
911-
* it is an auto-reload timer. It cannot be restarted here as the lists
912-
* have not yet been switched. */
913-
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
914-
915-
if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0 )
916-
{
917-
/* Calculate the reload value, and if the reload value results in
918-
* the timer going into the same timer list then it has already expired
919-
* and the timer should be re-inserted into the current list so it is
920-
* processed again within this loop. Otherwise a command should be sent
921-
* to restart the timer to ensure it is only inserted into a list after
922-
* the lists have been swapped. */
923-
xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
924-
925-
if( xReloadTime > xNextExpireTime )
926-
{
927-
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
928-
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
929-
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
930-
}
931-
else
932-
{
933-
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
934-
configASSERT( xResult );
935-
( void ) xResult;
936-
}
937-
}
938-
else
939-
{
940-
mtCOVERAGE_TEST_MARKER();
941-
}
913+
/* Process the expired timer. For auto-reload timers, be careful to
914+
* process only expirations that occur on the current list. Further
915+
* expirations must wait until after the lists are switched. */
916+
prvProcessExpiredTimer( xNextExpireTime, tmrMAX_TIME_BEFORE_OVERFLOW );
942917
}
943918

944919
pxTemp = pxCurrentTimerList;

0 commit comments

Comments
 (0)