From 81fec4bf328291c4b1517daee2ee49ee1b1a0c87 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Tue, 7 Jul 2026 12:50:50 +0200 Subject: [PATCH] fix(esp_timer): process ISR-dispatch timers in alarm thread on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On real hardware, ESP_TIMER_ISR callbacks run in a hardware interrupt that preempts any FreeRTOS task. On the Linux simulator, there are no real ISRs — the alarm is detected by a native pthread but was only forwarded to the FreeRTOS timer_task via xTaskNotifyGive(). This meant ISR-dispatch callbacks could be starved by higher-priority FreeRTOS tasks, breaking components like the task watchdog that rely on ISR-dispatch timers to detect scheduling starvation. Move ISR-dispatch timer processing into the alarm pthread itself, mirroring the hardware ISR path. The FreeRTOS timer_task is only notified when no ISR-dispatch timer consumed the alarm. This is safe because the Linux FreeRTOS port already handles vPortEnterCritical() calls from non-FreeRTOS threads (bumps nesting counter without blocking on scheduled-task checks). --- components/esp_timer/src/esp_timer.c | 14 +------------- components/esp_timer/src/esp_timer_impl_linux.c | 11 +++-------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/components/esp_timer/src/esp_timer.c b/components/esp_timer/src/esp_timer.c index 5be84f50aa2..8790f5b6315 100644 --- a/components/esp_timer/src/esp_timer.c +++ b/components/esp_timer/src/esp_timer.c @@ -551,12 +551,6 @@ static void timer_task(void* arg) while (true) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // all deferred events are processed at a time -#if CONFIG_ESP_TIMER_IMPL_LINUX && CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD - esp_timer_impl_try_to_set_next_alarm(); - if (timer_process_alarm(ESP_TIMER_ISR)) { - continue; - } -#endif timer_process_alarm(ESP_TIMER_TASK); } } @@ -571,7 +565,6 @@ ESP_TIMER_IRAM_ATTR void esp_timer_isr_dispatch_need_yield(void) } #endif -#ifndef CONFIG_ESP_TIMER_IMPL_LINUX static void ESP_TIMER_IRAM_ATTR timer_alarm_handler(void* arg) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; @@ -589,10 +582,9 @@ static void ESP_TIMER_IRAM_ATTR timer_alarm_handler(void* arg) vTaskNotifyGiveFromISR(s_timer_task, &xHigherPriorityTaskWoken); } if (xHigherPriorityTaskWoken == pdTRUE) { - portYIELD_FROM_ISR(); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } -#endif // !CONFIG_ESP_TIMER_IMPL_LINUX static ESP_TIMER_IRAM_ATTR inline bool is_initialized(void) { @@ -646,11 +638,7 @@ esp_err_t esp_timer_init(void) } #endif // CONFIG_ESP_TIMER_ISR_AFFINITY_NO_AFFINITY if (err == ESP_OK) { -#ifndef CONFIG_ESP_TIMER_IMPL_LINUX err = esp_timer_impl_init(&timer_alarm_handler); -#else - err = esp_timer_impl_init(NULL); -#endif if (err != ESP_OK) { ESP_EARLY_LOGE(TAG, "ISR init failed"); deinit_timer_task(); diff --git a/components/esp_timer/src/esp_timer_impl_linux.c b/components/esp_timer/src/esp_timer_impl_linux.c index a4f63e53d1a..7840ac40c2f 100644 --- a/components/esp_timer/src/esp_timer_impl_linux.c +++ b/components/esp_timer/src/esp_timer_impl_linux.c @@ -163,7 +163,7 @@ static esp_err_t program_timerfd(uint64_t deadline_us) static void *alarm_thread_func(void *arg) { - (void)arg; + intr_handler_t alarm_handler = (intr_handler_t)arg; #ifdef PR_SET_TIMERSLACK // Set timer slack to 1 ns for this thread. @@ -219,10 +219,7 @@ static void *alarm_thread_func(void *arg) continue; } - TaskHandle_t timer_task = esp_timer_impl_get_timer_task_handle(); - if (timer_task != NULL) { - xTaskNotifyGive(timer_task); - } + alarm_handler(NULL); } } @@ -300,8 +297,6 @@ esp_err_t esp_timer_impl_early_init(void) esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) { - (void)alarm_handler; - timestamp_id[0] = UINT64_MAX; timestamp_id[1] = UINT64_MAX; @@ -321,7 +316,7 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler) return ESP_FAIL; } - int err = pthread_create(&s_alarm_thread, NULL, alarm_thread_func, NULL); + int err = pthread_create(&s_alarm_thread, NULL, alarm_thread_func, alarm_handler); if (err != 0) { ESP_LOGE(TAG, "Failed to create alarm thread: %s", strerror(err));