fix(freertos): Fixed tickless idle tick count accounting

This commit fixes an issue where the FreeRTOS kernel does not account
for the pended ticks occuring during automatic light-sleep mode and
hence causing a jump in the tick count at a later stage in the
application lifetime.

Closes: https://github.com/espressif/esp-idf/issues/15642
This commit is contained in:
Sudeep Mohanty
2025-03-27 08:12:35 +01:00
committed by BOT
parent 11ea6924f7
commit 69d1c278b9

View File

@@ -3063,19 +3063,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char
/* Arrange for xTickCount to reach xNextTaskUnblockTime in /* Arrange for xTickCount to reach xNextTaskUnblockTime in
* xTaskIncrementTick() when the scheduler resumes. This ensures * xTaskIncrementTick() when the scheduler resumes. This ensures
* that any delayed tasks are resumed at the correct time. */ * that any delayed tasks are resumed at the correct time. */
#if ( configNUMBER_OF_CORES > 1 ) configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdTRUE );
{
/* In SMP, the entire tickless idle handling block
* is replaced with a critical section, taking the kernel lock. */
configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdFALSE );
}
#else /* configNUMBER_OF_CORES > 1 */
{
/* In single-core, the entire tickless idle handling block
* is done with scheduler suspended. */
configASSERT( taskIS_SCHEDULER_SUSPENDED() == pdTRUE );
}
#endif /* configNUMBER_OF_CORES > 1 */
configASSERT( xTicksToJump != ( TickType_t ) 0 ); configASSERT( xTicksToJump != ( TickType_t ) 0 );
xPendedTicks++; xPendedTicks++;
@@ -4332,31 +4320,37 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ) if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{ {
prvENTER_CRITICAL_OR_SUSPEND_ALL( &xKernelLock ); /* In SMP mode, the entire tickless idle handling block
* must be done with the kernel lock held. */
prvENTER_CRITICAL_SMP_ONLY( &xKernelLock );
{ {
/* Now the scheduler is suspended, the expected idle vTaskSuspendAll();
* time can be sampled again, and this time its value can
* be used. */
configASSERT( xNextTaskUnblockTime >= xTickCount );
xExpectedIdleTime = prvGetExpectedIdleTime();
/* Define the following macro to set xExpectedIdleTime to 0
* if the application does not want
* portSUPPRESS_TICKS_AND_SLEEP() to be called. */
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{ {
traceLOW_POWER_IDLE_BEGIN(); /* Now the scheduler is suspended, the expected idle
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); * time can be sampled again, and this time its value can
traceLOW_POWER_IDLE_END(); * be used. */
} configASSERT( xNextTaskUnblockTime >= xTickCount );
else xExpectedIdleTime = prvGetExpectedIdleTime();
{
mtCOVERAGE_TEST_MARKER(); /* Define the following macro to set xExpectedIdleTime to 0
* if the application does not want
* portSUPPRESS_TICKS_AND_SLEEP() to be called. */
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
traceLOW_POWER_IDLE_BEGIN();
portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );
traceLOW_POWER_IDLE_END();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
} }
( void ) xTaskResumeAll();
} }
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL( &xKernelLock ); prvEXIT_CRITICAL_SMP_ONLY( &xKernelLock );
} }
else else
{ {