diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index cd75859880..d1aa461d0e 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -196,14 +196,15 @@ void Application::process_dump_config_() { this->dump_config_at_++; } -void HOT Application::feed_wdt(uint32_t time) { - static uint32_t last_feed = 0; +void HOT Application::feed_wdt_slow_(uint32_t time) { // Use provided time if available, otherwise get current time uint32_t now = time ? time : millis(); - // Compare in milliseconds (3ms threshold) - if (now - last_feed > 3) { + // Compare in milliseconds (3ms threshold). The inline wrapper already + // performs this check when time != 0; repeat it here for the time == 0 + // entry and as a safety net. + if (now - this->last_wdt_feed_ > 3) { arch_feed_wdt(); - last_feed = now; + this->last_wdt_feed_ = now; #ifdef USE_STATUS_LED if (status_led::global_status_led != nullptr) { status_led::global_status_led->call(); diff --git a/esphome/core/application.h b/esphome/core/application.h index 6b2969b490..923cbfdb03 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -385,7 +385,19 @@ class Application { void schedule_dump_config() { this->dump_config_at_ = 0; } - void feed_wdt(uint32_t time = 0); + /// Feed the task watchdog. Hot-path inline rate-limit check: callers that + /// already have a timestamp in hand pay only a load + sub + branch on the + /// common (no-op) path. The actual arch feed + status LED update live in + /// feed_wdt_slow_ to keep this small enough to inline freely. + /// + /// Pass time==0 to request millis() be read for you (low-frequency callers + /// only — always takes the slow path). + void ESPHOME_ALWAYS_INLINE feed_wdt(uint32_t time = 0) { + if (time != 0 && static_cast(time - this->last_wdt_feed_) <= 3) { + return; + } + this->feed_wdt_slow_(time); + } void reboot(); @@ -615,7 +627,10 @@ class Application { /// Caller must ensure dump_config_at_ < components_.size(). void __attribute__((noinline)) process_dump_config_(); - void feed_wdt_arch_(); + /// Slow path for feed_wdt(): actually calls arch_feed_wdt(), updates + /// last_wdt_feed_, and re-dispatches the status LED. Out of line so the + /// inline wrapper stays tiny. + void feed_wdt_slow_(uint32_t time); /// Perform a delay while also monitoring socket file descriptors for readiness #ifdef USE_HOST @@ -669,6 +684,7 @@ class Application { // 4-byte members uint32_t last_loop_{0}; uint32_t loop_component_start_time_{0}; + uint32_t last_wdt_feed_{0}; // millis() of most recent arch_feed_wdt(); rate-limits feed_wdt() hot path #ifdef USE_HOST int max_fd_{-1}; // Highest file descriptor number for select()