From 1124804455f30f34cc5ae5c151f9b1b5fd96d525 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Tue, 8 Oct 2013 12:33:46 +0000 Subject: [PATCH] Add some defensive programming in the default tickless mode in case the application supplied post tick hook takes a long time to complete. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2057 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- FreeRTOS/Source/portable/GCC/ARM_CM3/port.c | 16 ++++++- FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c | 16 ++++++- FreeRTOS/Source/portable/IAR/ARM_CM3/port.c | 16 ++++++- FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c | 45 +++++++++++++++++-- FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c | 16 ++++++- FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c | 16 ++++++- 6 files changed, 112 insertions(+), 13 deletions(-) diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c index ed7b4e5e1..7603978c0 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c @@ -547,12 +547,24 @@ void xPortSysTickHandler( void ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { + unsigned long ulCalculatedLoadValue; + /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); - + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be processed as soon as this function exits, the tick value diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c index 0579ae929..ee9e36262 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM4F/port.c @@ -590,12 +590,24 @@ void xPortSysTickHandler( void ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { + unsigned long ulCalculatedLoadValue; + /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); - + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be processed as soon as this function exits, the tick value diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c index 3ed02de16..45f768f3a 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM3/port.c @@ -440,12 +440,24 @@ void xPortSysTickHandler( void ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { + unsigned long ulCalculatedLoadValue; + /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); - + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be processed as soon as this function exits, the tick value diff --git a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c index 3cdd25b30..21425e567 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CM4F/port.c @@ -154,6 +154,11 @@ extern void vPortStartFirstTask( void ); */ extern void vPortEnableVFP( void ); +/* + * Used to catch tasks that attempt to return from their implementing function. + */ +static void prvTaskExitError( void ); + /*-----------------------------------------------------------*/ /* @@ -208,7 +213,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxTopOfStack--; *pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* PC */ pxTopOfStack--; - *pxTopOfStack = 0; /* LR */ + *pxTopOfStack = ( portSTACK_TYPE ) prvTaskExitError; /* LR */ /* Save code space by skipping register initialisation. */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ @@ -225,6 +230,20 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE } /*-----------------------------------------------------------*/ +static void prvTaskExitError( void ) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT( uxCriticalNesting == ~0UL ); + portDISABLE_INTERRUPTS(); + for( ;; ); +} +/*-----------------------------------------------------------*/ + /* * See header file for description. */ @@ -393,9 +412,17 @@ void xPortSysTickHandler( void ) to be unsuspended then abandon the low power entry. */ if( eTaskConfirmSleepModeStatus() == eAbortSleep ) { + /* Restart from whatever is left in the count register to complete + this tick period. */ + portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG; + /* Restart SysTick. */ portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT; + /* Reset the reload register to the value required for normal tick + periods. */ + portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL; + /* Re-enable interrupts - see comments above __disable_interrupt() call above. */ __enable_interrupt(); @@ -439,12 +466,24 @@ void xPortSysTickHandler( void ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { + unsigned long ulCalculatedLoadValue; + /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); - + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be processed as soon as this function exits, the tick value diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c index 9d1e53e67..5e4c2b31d 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM3/port.c @@ -516,12 +516,24 @@ void xPortSysTickHandler( void ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { + unsigned long ulCalculatedLoadValue; + /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); - + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be processed as soon as this function exits, the tick value diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c index a5b81f7bc..21f1a3be5 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c @@ -587,12 +587,24 @@ void xPortSysTickHandler( void ) if( ( portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT ) != 0 ) { + unsigned long ulCalculatedLoadValue; + /* The tick interrupt has already executed, and the SysTick count reloaded with ulReloadValue. Reset the portNVIC_SYSTICK_LOAD_REG with whatever remains of this tick period. */ - portNVIC_SYSTICK_LOAD_REG = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); - + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ) - ( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG ); + + /* Don't allow a tiny value, or values that have somehow + underflowed because the post sleep hook did something + that took too long. */ + if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) || ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ) + { + ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL ); + } + + portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue; + /* The tick interrupt handler will already have pended the tick processing in the kernel. As the pending tick will be processed as soon as this function exits, the tick value -- 2.39.5