X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=FreeRTOS%2FSource%2Ftimers.c;h=12a2f4e9b6a6213d1befd75a5a3fa61d6e076390;hb=03e994cd3c20d0c4cb101923e06c4dcd7376b132;hp=b86e1ba214dc31af6c0eaee92b2c908cbd2daf26;hpb=bdbea5c524580e0524bf071887b8429769fc8cec;p=freertos diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c index b86e1ba21..12a2f4e9b 100644 --- a/FreeRTOS/Source/timers.c +++ b/FreeRTOS/Source/timers.c @@ -1,6 +1,6 @@ /* - * FreeRTOS Kernel V10.0.0 - * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@ -10,8 +10,7 @@ * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. If you wish to use our Amazon - * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS @@ -43,11 +42,11 @@ task.h is included from an application file. */ #error configUSE_TIMERS must be set to 1 to make the xTimerPendFunctionCall() function available. #endif -/* Lint e961 and e750 are suppressed as a MISRA exception justified because the -MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the -header files above, but not in this file, in order to generate the correct -privileged Vs unprivileged linkage and placement. */ -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */ +/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified +because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined +for the header files above, but not in this file, in order to generate the +correct privileged Vs unprivileged linkage and placement. */ +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */ /* This entire source file will be skipped if the application is not configured @@ -65,22 +64,23 @@ defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ #define configTIMER_SERVICE_TASK_NAME "Tmr Svc" #endif +/* Bit definitions used in the ucStatus member of a timer structure. */ +#define tmrSTATUS_IS_ACTIVE ( ( uint8_t ) 0x01 ) +#define tmrSTATUS_IS_STATICALLY_ALLOCATED ( ( uint8_t ) 0x02 ) +#define tmrSTATUS_IS_AUTORELOAD ( ( uint8_t ) 0x04 ) + /* The definition of the timers themselves. */ -typedef struct tmrTimerControl +typedef struct tmrTimerControl /* The old naming convention is used to prevent breaking kernel aware debuggers. */ { const char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ ListItem_t xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */ TickType_t xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */ - UBaseType_t uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one-shot timer. */ void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */ TimerCallbackFunction_t pxCallbackFunction; /*<< The function that will be called when the timer expires. */ #if( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxTimerNumber; /*<< An ID assigned by trace tools such as FreeRTOS+Trace */ #endif - - #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) - uint8_t ucStaticallyAllocated; /*<< Set to pdTRUE if the timer was created statically so no attempt is made to free the memory again if the timer is later deleted. */ - #endif + uint8_t ucStatus; /*<< Holds bits to say if the timer was statically allocated or not, and if it is active or not. */ } xTIMER; /* The old xTIMER name is maintained above then typedefed to the new Timer_t @@ -128,7 +128,10 @@ which static variables must be declared volatile. */ /* 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 these lists. */ +timer service task is allowed to access these lists. +xActiveTimerList1 and xActiveTimerList2 could be at function scope but that +breaks some kernel aware debuggers, and debuggers that reply on removing the +static qualifier. */ PRIVILEGED_DATA static List_t xActiveTimerList1; PRIVILEGED_DATA static List_t xActiveTimerList2; PRIVILEGED_DATA static List_t *pxCurrentTimerList; @@ -163,7 +166,7 @@ static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION; * task. Other tasks communicate with the timer service task using the * xTimerQueue queue. */ -static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION; +static portTASK_FUNCTION_PROTO( prvTimerTask, pvParameters ) PRIVILEGED_FUNCTION; /* * Called by the timer service task to interpret and process a command it @@ -179,7 +182,7 @@ static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const Tic /* * 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( const TickType_t xNextExpireTime, const TickType_t xTimeNow ) PRIVILEGED_FUNCTION; @@ -284,26 +287,21 @@ BaseType_t xReturn = pdFAIL; { Timer_t *pxNewTimer; - pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); + pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of Timer_t is always a pointer to the timer's mame. */ if( pxNewTimer != NULL ) { + /* Status is thus far zero as the timer is not created statically + and has not been started. The auto-reload bit may get set in + prvInitialiseNewTimer. */ + pxNewTimer->ucStatus = 0x00; prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); - - #if( configSUPPORT_STATIC_ALLOCATION == 1 ) - { - /* Timers can be created statically or dynamically, so note this - timer was created dynamically in case the timer is later - deleted. */ - pxNewTimer->ucStaticallyAllocated = pdFALSE; - } - #endif /* configSUPPORT_STATIC_ALLOCATION */ } return pxNewTimer; } -#endif /* configSUPPORT_STATIC_ALLOCATION */ +#endif /* configSUPPORT_DYNAMIC_ALLOCATION */ /*-----------------------------------------------------------*/ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) @@ -324,24 +322,22 @@ BaseType_t xReturn = pdFAIL; structure. */ volatile size_t xSize = sizeof( StaticTimer_t ); configASSERT( xSize == sizeof( Timer_t ) ); + ( void ) xSize; /* Keeps lint quiet when configASSERT() is not defined. */ } #endif /* configASSERT_DEFINED */ /* A pointer to a StaticTimer_t structure MUST be provided, use it. */ configASSERT( pxTimerBuffer ); - pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */ + pxNewTimer = ( Timer_t * ) pxTimerBuffer; /*lint !e740 !e9087 StaticTimer_t is a pointer to a Timer_t, so guaranteed to be aligned and sized correctly (checked by an assert()), so this is safe. */ if( pxNewTimer != NULL ) { - prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); + /* Timers can be created statically or dynamically so note this + timer was created statically in case it is later deleted. The + auto-reload bit may get set in prvInitialiseNewTimer(). */ + pxNewTimer->ucStatus = tmrSTATUS_IS_STATICALLY_ALLOCATED; - #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - { - /* Timers can be created statically or dynamically so note this - timer was created statically in case it is later deleted. */ - pxNewTimer->ucStaticallyAllocated = pdTRUE; - } - #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ + prvInitialiseNewTimer( pcTimerName, xTimerPeriodInTicks, uxAutoReload, pvTimerID, pxCallbackFunction, pxNewTimer ); } return pxNewTimer; @@ -370,10 +366,13 @@ static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e97 parameters. */ pxNewTimer->pcTimerName = pcTimerName; pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks; - pxNewTimer->uxAutoReload = uxAutoReload; pxNewTimer->pvTimerID = pvTimerID; pxNewTimer->pxCallbackFunction = pxCallbackFunction; vListInitialiseItem( &( pxNewTimer->xTimerListItem ) ); + if( uxAutoReload != pdFALSE ) + { + pxNewTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; + } traceTIMER_CREATE( pxNewTimer ); } } @@ -393,7 +392,7 @@ DaemonTaskMessage_t xMessage; /* Send a command to the timer service task to start the xTimer timer. */ xMessage.xMessageID = xCommandID; xMessage.u.xTimerParameters.xMessageValue = xOptionalValue; - xMessage.u.xTimerParameters.pxTimer = ( Timer_t * ) xTimer; + xMessage.u.xTimerParameters.pxTimer = xTimer; if( xCommandID < tmrFIRST_FROM_ISR_COMMAND ) { @@ -433,16 +432,61 @@ TaskHandle_t xTimerGetTimerDaemonTaskHandle( void ) TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) { -Timer_t *pxTimer = ( Timer_t * ) xTimer; +Timer_t *pxTimer = xTimer; configASSERT( xTimer ); return pxTimer->xTimerPeriodInTicks; } /*-----------------------------------------------------------*/ +void vTimerSetReloadMode( TimerHandle_t xTimer, const UBaseType_t uxAutoReload ) +{ +Timer_t * pxTimer = xTimer; + + configASSERT( xTimer ); + taskENTER_CRITICAL(); + { + if( uxAutoReload != pdFALSE ) + { + pxTimer->ucStatus |= tmrSTATUS_IS_AUTORELOAD; + } + else + { + pxTimer->ucStatus &= ~tmrSTATUS_IS_AUTORELOAD; + } + } + taskEXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxTimerGetReloadMode( TimerHandle_t xTimer ) +{ +Timer_t * pxTimer = xTimer; +UBaseType_t uxReturn; + + configASSERT( xTimer ); + taskENTER_CRITICAL(); + { + if( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) == 0 ) + { + /* Not an auto-reload timer. */ + uxReturn = ( UBaseType_t ) pdFALSE; + } + else + { + /* Is an auto-reload timer. */ + uxReturn = ( UBaseType_t ) pdTRUE; + } + } + taskEXIT_CRITICAL(); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) { -Timer_t * pxTimer = ( Timer_t * ) xTimer; +Timer_t * pxTimer = xTimer; TickType_t xReturn; configASSERT( xTimer ); @@ -453,7 +497,7 @@ TickType_t xReturn; const char * pcTimerGetName( TimerHandle_t xTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ { -Timer_t *pxTimer = ( Timer_t * ) xTimer; +Timer_t *pxTimer = xTimer; configASSERT( xTimer ); return pxTimer->pcTimerName; @@ -463,16 +507,16 @@ Timer_t *pxTimer = ( Timer_t * ) xTimer; 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 ); +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 + /* 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 == ( UBaseType_t ) pdTRUE ) + 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 @@ -492,6 +536,7 @@ Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTi } else { + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; mtCOVERAGE_TEST_MARKER(); } @@ -500,7 +545,7 @@ Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTi } /*-----------------------------------------------------------*/ -static void prvTimerTask( void *pvParameters ) +static portTASK_FUNCTION( prvTimerTask, pvParameters ) { TickType_t xNextExpireTime; BaseType_t xListWasEmpty; @@ -748,11 +793,12 @@ TickType_t xTimeNow; switch( xMessage.xMessageID ) { case tmrCOMMAND_START : - case tmrCOMMAND_START_FROM_ISR : - case tmrCOMMAND_RESET : - case tmrCOMMAND_RESET_FROM_ISR : + 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; if( prvInsertTimerInActiveList( pxTimer, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) != pdFALSE ) { /* The timer expired before it was added to the active @@ -760,7 +806,7 @@ TickType_t xTimeNow; pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); traceTIMER_EXPIRED( pxTimer ); - if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + 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 ); @@ -779,12 +825,13 @@ TickType_t xTimeNow; case tmrCOMMAND_STOP : case tmrCOMMAND_STOP_FROM_ISR : - /* The timer has already been removed from the active list. - There is nothing to do here. */ + /* The timer has already been removed from the active list. */ + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; break; case tmrCOMMAND_CHANGE_PERIOD : case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR : + pxTimer->ucStatus |= tmrSTATUS_IS_ACTIVE; pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue; configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) ); @@ -798,29 +845,28 @@ TickType_t xTimeNow; break; case tmrCOMMAND_DELETE : - /* The timer has already been removed from the active list, - just free up the memory if the memory was dynamically - allocated. */ - #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) + #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) { - /* The timer can only have been allocated dynamically - - free it again. */ - vPortFree( pxTimer ); - } - #elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) - { - /* The timer could have been allocated statically or - dynamically, so check before attempting to free the - memory. */ - if( pxTimer->ucStaticallyAllocated == ( uint8_t ) pdFALSE ) + /* The timer has already been removed from the active list, + just free up the memory if the memory was dynamically + allocated. */ + if( ( pxTimer->ucStatus & tmrSTATUS_IS_STATICALLY_ALLOCATED ) == ( uint8_t ) 0 ) { vPortFree( pxTimer ); } else { - mtCOVERAGE_TEST_MARKER(); + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; } } + #else + { + /* If dynamic allocation is not enabled, the memory + could not have been dynamically allocated. So there is + no need to free the memory - just mark the timer as + "not active". */ + pxTimer->ucStatus &= ~tmrSTATUS_IS_ACTIVE; + } #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ break; @@ -849,7 +895,7 @@ BaseType_t xResult; xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList ); /* Remove the timer from the list. */ - pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList ); + 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 ); @@ -858,7 +904,7 @@ BaseType_t xResult; have not yet been switched. */ pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer ); - if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE ) + 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 @@ -945,28 +991,32 @@ static void prvCheckForValidListAndQueue( void ) BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) { -BaseType_t xTimerIsInActiveList; -Timer_t *pxTimer = ( Timer_t * ) xTimer; +BaseType_t xReturn; +Timer_t *pxTimer = xTimer; configASSERT( xTimer ); /* Is the timer in the list of active timers? */ taskENTER_CRITICAL(); { - /* 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 = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); /*lint !e961. Cast is only redundant when NULL is passed into the macro. */ + if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } } taskEXIT_CRITICAL(); - return xTimerIsInActiveList; + return xReturn; } /*lint !e818 Can't be pointer to const due to the typedef. */ /*-----------------------------------------------------------*/ void *pvTimerGetTimerID( const TimerHandle_t xTimer ) { -Timer_t * const pxTimer = ( Timer_t * ) xTimer; +Timer_t * const pxTimer = xTimer; void *pvReturn; configASSERT( xTimer ); @@ -983,7 +1033,7 @@ void *pvReturn; void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID ) { -Timer_t * const pxTimer = ( Timer_t * ) xTimer; +Timer_t * const pxTimer = xTimer; configASSERT( xTimer );