From f69d77bcb6f9c347751d41abab18a6a763ffd618 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Thu, 27 Mar 2025 08:12:35 +0100 Subject: [PATCH] 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 --- components/freertos/FreeRTOS-Kernel/tasks.c | 62 ++++++++++----------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/tasks.c b/components/freertos/FreeRTOS-Kernel/tasks.c index 368a20599f..4d1138a8d7 100644 --- a/components/freertos/FreeRTOS-Kernel/tasks.c +++ b/components/freertos/FreeRTOS-Kernel/tasks.c @@ -3063,19 +3063,7 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char /* Arrange for xTickCount to reach xNextTaskUnblockTime in * xTaskIncrementTick() when the scheduler resumes. This ensures * that any delayed tasks are resumed at the correct time. */ - #if ( configNUMBER_OF_CORES > 1 ) - { - /* 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( taskIS_SCHEDULER_SUSPENDED() == pdTRUE ); configASSERT( xTicksToJump != ( TickType_t ) 0 ); xPendedTicks++; @@ -4369,31 +4357,37 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) 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 - * 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 ) + vTaskSuspendAll(); { - traceLOW_POWER_IDLE_BEGIN(); - portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ); - traceLOW_POWER_IDLE_END(); - } - else - { - mtCOVERAGE_TEST_MARKER(); + /* Now the scheduler is suspended, the expected idle + * 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(); + 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 {