mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 02:30:52 +03:00
fix(esp_timer): Fix esp_timer task dispatch stall
The task dispatch method for the esp_timer could stall even if it is armed if ther ISR dispatch alarm triggers close to the task dispatch. This MR fixes a bug where the esp_timer cleared the incorrect cached array timer index and subsequently the timer task is never woken up. Closes https://github.com/espressif/esp-idf/issues/18808
This commit is contained in:
committed by
Konstantin Kondrashov
parent
d450308955
commit
958dc8afcf
@@ -476,13 +476,11 @@ static ESP_TIMER_IRAM_ATTR void timer_list_unlock(esp_timer_dispatch_t timer_typ
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
static ESP_TIMER_IRAM_ATTR bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
#else
|
||||
static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
ESP_TIMER_IRAM_ATTR
|
||||
#endif
|
||||
static void timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
{
|
||||
timer_list_lock(dispatch_method);
|
||||
bool processed = false;
|
||||
esp_timer_handle_t it;
|
||||
while (1) {
|
||||
it = LIST_FIRST(&s_timers[dispatch_method]);
|
||||
@@ -492,7 +490,6 @@ static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
break;
|
||||
}
|
||||
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-use-after-free")
|
||||
processed = true;
|
||||
LIST_REMOVE(it, list_entry);
|
||||
if (it->event_id == EVENT_ID_DELETE_TIMER) {
|
||||
// It is handled only by ESP_TIMER_TASK (see esp_timer_delete()).
|
||||
@@ -534,17 +531,9 @@ static bool timer_process_alarm(esp_timer_dispatch_t dispatch_method)
|
||||
#endif
|
||||
}
|
||||
} // while(1)
|
||||
if (it) {
|
||||
if (dispatch_method == ESP_TIMER_TASK || (dispatch_method != ESP_TIMER_TASK && processed == true)) {
|
||||
esp_timer_impl_set_alarm_id(it->alarm, dispatch_method);
|
||||
}
|
||||
} else {
|
||||
if (processed) {
|
||||
esp_timer_impl_set_alarm_id(UINT64_MAX, dispatch_method);
|
||||
}
|
||||
}
|
||||
uint64_t next_alarm = (it != NULL) ? it->alarm : UINT64_MAX;
|
||||
esp_timer_impl_set_alarm_id(next_alarm, dispatch_method);
|
||||
timer_list_unlock(dispatch_method);
|
||||
return processed;
|
||||
}
|
||||
|
||||
static void timer_task(void* arg)
|
||||
@@ -564,24 +553,30 @@ ESP_TIMER_IRAM_ATTR void esp_timer_isr_dispatch_need_yield(void)
|
||||
#endif
|
||||
s_isr_dispatch_need_yield = pdTRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ESP_TIMER_IRAM_ATTR timer_alarm_handler(void* arg)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
bool isr_timers_processed = false;
|
||||
|
||||
#ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
||||
esp_timer_impl_try_to_set_next_alarm();
|
||||
// process timers with ISR dispatch method
|
||||
isr_timers_processed = timer_process_alarm(ESP_TIMER_ISR);
|
||||
uint32_t due_alarm_mask = esp_timer_impl_claim_due_alarms();
|
||||
|
||||
if (due_alarm_mask & (1U << ESP_TIMER_ISR)) {
|
||||
timer_process_alarm(ESP_TIMER_ISR);
|
||||
}
|
||||
|
||||
xHigherPriorityTaskWoken = s_isr_dispatch_need_yield;
|
||||
s_isr_dispatch_need_yield = pdFALSE;
|
||||
#endif
|
||||
|
||||
if (isr_timers_processed == false) {
|
||||
if (due_alarm_mask & (1U << ESP_TIMER_TASK)) {
|
||||
vTaskNotifyGiveFromISR(s_timer_task, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
#else
|
||||
vTaskNotifyGiveFromISR(s_timer_task, &xHigherPriorityTaskWoken);
|
||||
#endif
|
||||
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user