From f8a1c54690fa58eed69ba462229a93091e1463e4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 10 Apr 2026 17:44:18 -1000 Subject: [PATCH] [esphome.ota] Document NULL-fallback degraded mode for listener filter Per review feedback: if esphome_lwip_get_sock() ever returned nullptr (shouldn't after successful listen(), but defensively), the listener filter compare would never match and no fast-select wakes would fire. loop()'s self-disable safety net + the first-tick-after-setup window cover that degraded mode correctly. Spell it out in the comment so a future reader doesn't treat the nullptr path as a silent bug. --- esphome/components/esphome/ota/ota_esphome.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/esphome/ota/ota_esphome.cpp b/esphome/components/esphome/ota/ota_esphome.cpp index 408bde14ac..2e2c0bc73b 100644 --- a/esphome/components/esphome/ota/ota_esphome.cpp +++ b/esphome/components/esphome/ota/ota_esphome.cpp @@ -76,10 +76,15 @@ void ESPHomeOTAComponent::setup() { // Install the listener filter so the fast-select RCVPLUS wake hook only fires for // events on this listener's netconn (i.e. new incoming connections). Without this, // every RCVPLUS across all monitored sockets (API client data, mDNS, etc.) would - // pay the inline hook's two volatile stores + memw barriers to mark OTA - // pending-enable, even though OTA would just re-disable itself on the next tick. - // Uses the existing public esphome_lwip_get_sock() lookup instead of adding a - // dedicated accessor on Socket — the lookup happens once at setup, not per event. + // pay the wake hook cost to mark OTA pending-enable, even though OTA would just + // re-disable itself on the next tick. Uses the existing public esphome_lwip_get_sock() + // lookup instead of adding a dedicated accessor on Socket — the lookup happens once + // at setup, not per event. If the lookup ever returns nullptr (shouldn't after a + // successful listen()), the filter is installed with nullptr and the callback + // compare never matches, so no wakes fire — loop() falls back to the self-disable + // safety net. That degraded mode is the correct behavior: OTA will still work on + // the first loop tick (which runs during setup before disable), and any subsequent + // wakes go through the wake_loop_any_context() path that fires unconditionally. esphome_fast_select_set_ota_listener_sock(esphome_lwip_get_sock(this->server_->get_fd())); #endif }