From e1b98f0b4be153cf6590c5b5b2f76b001af71c51 Mon Sep 17 00:00:00 2001 From: RichardBarry Date: Fri, 28 Feb 2020 12:40:11 -0800 Subject: [PATCH] This change prevents tickless idle mode potentially sleeping for an extra tick in the corer case that a tick interrupt occurred between the scheduler being suspended and the expected idle time being checked for a second time (within the idle task) - as described by the sequence below. Th change updates eTaskConfirmSleepModeStatus() to specifically check if a tick is pending, and if so, abort entering sleep mode. + The idle task decides to enter sleep mode on the following line. ``` if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) ``` + The scheduler is suspended, preventing any context switches. [Potentially a tick interrupt could occur here. That could happen if other tasks executing consumed a lot of time since the above code line executed. If a tick interrupt occurs here the interrupt will be entered but the interrupt will not do anything other than increment xPendedTicks.] + The expected idle time is checked again. No context switches can occur now so the code will execute until the scheduler is unsuspended. Assuming configEXPECTED_IDLE_TIME_BEFORE_SLEEP is set to a sensible value, a tick interrupt won't occur for some time. + portSUPPRESS_TICKS_AND_SLEEP() is called. + The default implementation of the tickless function calls eTaskConfirmSleep() - which prior to this change does not return eAbortSleep even though xPendedTicks is not 0, and after this change does return eAbortSleep. --- tasks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tasks.c b/tasks.c index f93fca039..d83db4b53 100644 --- a/tasks.c +++ b/tasks.c @@ -3526,6 +3526,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) /* A yield was pended while the scheduler was suspended. */ eReturn = eAbortSleep; } + else if( xPendedTicks != 0 ) + { + /* A tick interrupt has already occurred but was held pending + because the scheduler is suspended. */ + eReturn = eAbortSleep; + } else { /* If all the tasks are in the suspended list (which might mean they