summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Tenney <jeff.tenney@gmail.com>2021-04-12 16:39:17 -0700
committerGitHub <noreply@github.com>2021-04-12 16:39:17 -0700
commitf2bcfb3866221bfa8b3859f2c8171a8b2c196530 (patch)
treedeb456cee138f53d2d1ac7f722079ca2ab1c3467
parent1f47a22b23d2fa2188a78fb477d10f8c0768536a (diff)
downloadfreertos-git-f2bcfb3866221bfa8b3859f2c8171a8b2c196530.tar.gz
Add test for backlogged auto-reload timer (#553)
* Add test for backlogged auto-reset timer Must call vTimerDemoIncludeBacklogTests() to activate. * Fix little style issues - Update to new header - Add parentheses (style) - Remove trailing space accidentally introduced * Don't verify full clearing of backlog The timer task should be free to process the stop request without a specific requirement to work through the backlog of callbacks for the stopped timer. The timer task should be allowed to cancel the entire backlog, part of it, or none of it. In other words, once the application sends the stop request, it should not depend on receiving any more callbacks, even backlogged ones. The only requirement here is that the timer stop as requested. Co-authored-by: Joseph Julicher <jjulicher@mac.com> Co-authored-by: Cobus van Eeden <35851496+cobusve@users.noreply.github.com>
-rw-r--r--FreeRTOS/Demo/Common/Minimal/TimerDemo.c96
-rw-r--r--FreeRTOS/Demo/Common/include/TimerDemo.h6
2 files changed, 94 insertions, 8 deletions
diff --git a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c
index 1115b8bf4..70a1eec30 100644
--- a/FreeRTOS/Demo/Common/Minimal/TimerDemo.c
+++ b/FreeRTOS/Demo/Common/Minimal/TimerDemo.c
@@ -19,10 +19,9 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * http://www.FreeRTOS.org
- * http://aws.amazon.com/freertos
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
*
- * 1 tab == 4 spaces!
*/
@@ -78,6 +77,7 @@ static void prvTest3_CheckAutoReloadExpireRates( void );
static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );
static void prvTest5_CheckBasicOneShotTimerBehaviour( void );
static void prvTest6_CheckAutoReloadResetBehaviour( void );
+static void prvTest7_CheckBacklogBehaviour( void );
static void prvResetStartConditionsForNextIteration( void );
/*-----------------------------------------------------------*/
@@ -86,16 +86,24 @@ static void prvResetStartConditionsForNextIteration( void );
detected in any of the demo tests. */
static volatile BaseType_t xTestStatus = pdPASS;
+/* Flag indicating whether the testing includes the backlog demo. The backlog
+demo can be disruptive to other demos because the timer backlog is created by
+calling xTaskCatchUpTicks(). */
+static uint8_t ucIsBacklogDemoEnabled = ( uint8_t ) pdFALSE;
+
/* Counter that is incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulLoopCounter = 0;
/* A set of auto-reload timers - each of which use the same callback function.
The callback function uses the timer ID to index into, and then increment, a
-counter in the ucAutoReloadTimerCounters[] array. The auto-reload timers
-referenced from xAutoReloadTimers[] are used by the prvTimerTestTask task. */
+counter in the ucAutoReloadTimerCounters[] array. The callback function stops
+xAutoReloadTimers[0] during its callback if ucIsStopNeededInTimerZeroCallback is
+pdTRUE. The auto-reload timers referenced from xAutoReloadTimers[] are used by
+the prvTimerTestTask task. */
static TimerHandle_t xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
static uint8_t ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
+static uint8_t ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdFALSE;
/* The one-shot timer is configured to use a callback function that increments
ucOneShotTimerCounter each time it gets called. */
@@ -146,6 +154,12 @@ void vStartTimerDemoTask( TickType_t xBasePeriodIn )
}
/*-----------------------------------------------------------*/
+void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests )
+{
+ ucIsBacklogDemoEnabled = ( uint8_t ) includeBacklogTests;
+}
+/*-----------------------------------------------------------*/
+
static void prvTimerTestTask( void *pvParameters )
{
( void ) pvParameters;
@@ -199,6 +213,12 @@ static void prvTimerTestTask( void *pvParameters )
/* Check timer reset behaviour. */
prvTest6_CheckAutoReloadResetBehaviour();
+ /* Check timer behaviour when the timer task gets behind in its work. */
+ if ( ucIsBacklogDemoEnabled == ( uint8_t ) pdTRUE )
+ {
+ prvTest7_CheckBacklogBehaviour();
+ }
+
/* Start the timers again to restart all the tests over again. */
prvResetStartConditionsForNextIteration();
}
@@ -664,6 +684,65 @@ uint8_t ucTimer;
}
/*-----------------------------------------------------------*/
+static void prvTest7_CheckBacklogBehaviour( void )
+{
+ /* Use the first auto-reload timer to test stopping a timer from a
+ backlogged callback. */
+
+ /* The timer has not been started yet! */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Prompt the callback function to stop the timer. */
+ ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdTRUE;
+
+ /* Now start the timer. This will appear to happen immediately to
+ this task because this task is running at a priority below the timer
+ service task. Use a timer period of one tick so the call to
+ xTaskCatchUpTicks() below has minimal impact on other tests that might
+ be running. */
+ #define tmrdemoBACKLOG_TIMER_PERIOD ( ( TickType_t ) 1 )
+ xTimerChangePeriod( xAutoReloadTimers[ 0 ], tmrdemoBACKLOG_TIMER_PERIOD, tmrdemoDONT_BLOCK );
+
+ /* The timer should now be active. */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Arrange for the callback to execute late enough that it will execute
+ twice, back-to-back. The timer must handle the stop request properly
+ in spite of the backlog of callbacks. */
+ #define tmrdemoEXPECTED_BACKLOG_EXPIRIES ( ( TickType_t ) 2 )
+ xTaskCatchUpTicks( tmrdemoBACKLOG_TIMER_PERIOD * tmrdemoEXPECTED_BACKLOG_EXPIRIES );
+
+ /* The timer should now be inactive. */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Restore the standard timer period, and leave the timer inactive. */
+ xTimerChangePeriod( xAutoReloadTimers[ 0 ], xBasePeriod, tmrdemoDONT_BLOCK );
+ xTimerStop( xAutoReloadTimers[ 0 ], tmrdemoDONT_BLOCK );
+
+ /* Clear the reload count for the timer used in this test. */
+ ucAutoReloadTimerCounters[ 0 ] = ( uint8_t ) 0;
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so the check
+ task knows this task is still running. */
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
static void prvResetStartConditionsForNextIteration( void )
{
uint8_t ucTimer;
@@ -1026,6 +1105,13 @@ size_t uxTimerID;
if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
{
( ucAutoReloadTimerCounters[ uxTimerID ] )++;
+
+ /* Stop timer ID 0 if requested. */
+ if ( ( uxTimerID == ( size_t ) 0 ) && ( ucIsStopNeededInTimerZeroCallback == ( uint8_t ) pdTRUE ) )
+ {
+ xTimerStop( pxExpiredTimer, tmrdemoDONT_BLOCK );
+ ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdFALSE;
+ }
}
else
{
diff --git a/FreeRTOS/Demo/Common/include/TimerDemo.h b/FreeRTOS/Demo/Common/include/TimerDemo.h
index cdd0c6d5c..aba9d7977 100644
--- a/FreeRTOS/Demo/Common/include/TimerDemo.h
+++ b/FreeRTOS/Demo/Common/include/TimerDemo.h
@@ -19,10 +19,9 @@
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * http://www.FreeRTOS.org
- * http://aws.amazon.com/freertos
+ * https://www.FreeRTOS.org
+ * https://github.com/FreeRTOS
*
- * 1 tab == 4 spaces!
*/
#ifndef TIMER_DEMO_H
@@ -31,6 +30,7 @@
void vStartTimerDemoTask( TickType_t xBaseFrequencyIn );
BaseType_t xAreTimerDemoTasksStillRunning( TickType_t xCycleFrequency );
void vTimerPeriodicISRTests( void );
+void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests );
#endif /* TIMER_DEMO_H */