diff --git a/esphome/components/esp8266/helpers.cpp b/esphome/components/esp8266/helpers.cpp index 4c849948fd..4f07ca69b5 100644 --- a/esphome/components/esp8266/helpers.cpp +++ b/esphome/components/esp8266/helpers.cpp @@ -17,9 +17,7 @@ bool random_bytes(uint8_t *data, size_t len) { return os_get_random(data, len) = IRAM_ATTR InterruptLock::InterruptLock() { state_ = xt_rsil(15); } IRAM_ATTR InterruptLock::~InterruptLock() { xt_wsr_ps(state_); } -// ESP8266 doesn't support lwIP core locking, so this is a no-op -LwIPLock::LwIPLock() {} -LwIPLock::~LwIPLock() {} +// ESP8266 LwIPLock is defined inline as a no-op in helpers.h void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) wifi_get_macaddr(STATION_IF, mac); diff --git a/esphome/components/libretiny/helpers.cpp b/esphome/components/libretiny/helpers.cpp index 37ae0fb455..21913e4a16 100644 --- a/esphome/components/libretiny/helpers.cpp +++ b/esphome/components/libretiny/helpers.cpp @@ -26,9 +26,7 @@ void Mutex::unlock() { xSemaphoreGive(this->handle_); } IRAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); } IRAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); } -// LibreTiny doesn't support lwIP core locking, so this is a no-op -LwIPLock::LwIPLock() {} -LwIPLock::~LwIPLock() {} +// LibreTiny LwIPLock is defined inline as a no-op in helpers.h void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) WiFi.macAddress(mac); diff --git a/esphome/components/rp2040/helpers.cpp b/esphome/components/rp2040/helpers.cpp index 3d71b7a5cc..50f8715b4f 100644 --- a/esphome/components/rp2040/helpers.cpp +++ b/esphome/components/rp2040/helpers.cpp @@ -47,14 +47,11 @@ IRAM_ATTR InterruptLock::~InterruptLock() { restore_interrupts(state_); } // async_context recursive mutex to prevent IRQ callbacks from firing during // critical sections. See esphome#10681. // -// When CYW43 is not available (non-WiFi RP2040 boards), this is a no-op since -// there's no network stack and no lwip callbacks to race with. +// When CYW43 is not available (non-WiFi RP2040 boards), LwIPLock is +// defined inline as a no-op in helpers.h. #if defined(USE_WIFI) LwIPLock::LwIPLock() { cyw43_arch_lwip_begin(); } LwIPLock::~LwIPLock() { cyw43_arch_lwip_end(); } -#else -LwIPLock::LwIPLock() {} -LwIPLock::~LwIPLock() {} #endif void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter) diff --git a/esphome/components/zephyr/core.cpp b/esphome/components/zephyr/core.cpp index eee7fb3f4f..1d105a1057 100644 --- a/esphome/components/zephyr/core.cpp +++ b/esphome/components/zephyr/core.cpp @@ -76,9 +76,7 @@ void Mutex::unlock() { k_mutex_unlock(static_cast(this->handle_)); } IRAM_ATTR InterruptLock::InterruptLock() { state_ = irq_lock(); } IRAM_ATTR InterruptLock::~InterruptLock() { irq_unlock(state_); } -// Zephyr doesn't support lwIP core locking, so this is a no-op -LwIPLock::LwIPLock() {} -LwIPLock::~LwIPLock() {} +// Zephyr LwIPLock is defined inline as a no-op in helpers.h uint32_t random_uint32() { return rand(); } // NOLINT(cert-msc30-c, cert-msc50-cpp) bool random_bytes(uint8_t *data, size_t len) { diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 0bb205f035..b2de8e8d76 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -1946,19 +1946,26 @@ class InterruptLock { /** Helper class to lock the lwIP TCPIP core when making lwIP API calls from non-TCPIP threads. * - * This is needed on multi-threaded platforms (ESP32) when CONFIG_LWIP_TCPIP_CORE_LOCKING is enabled. - * It ensures thread-safe access to lwIP APIs. + * This is needed on multi-threaded platforms (ESP32) when CONFIG_LWIP_TCPIP_CORE_LOCKING is enabled, + * and on RP2040 when CYW43 WiFi is active (cyw43_arch_lwip_begin/end). * - * @note This follows the same pattern as InterruptLock - platform-specific implementations in helpers.cpp + * On single-threaded platforms without lwIP core locking (ESP8266, LibreTiny, Zephyr), + * this is a no-op defined inline so the compiler can eliminate all call overhead. */ class LwIPLock { public: - LwIPLock(); - ~LwIPLock(); - - // Delete copy constructor and copy assignment operator to prevent accidental copying LwIPLock(const LwIPLock &) = delete; LwIPLock &operator=(const LwIPLock &) = delete; + +#if defined(USE_ESP32) || (defined(USE_RP2040) && defined(USE_WIFI)) + // Platforms with real lwIP locking — out-of-line implementations in helpers.cpp + LwIPLock(); + ~LwIPLock(); +#else + // Single-threaded or no lwIP core locking — inline no-ops + LwIPLock() = default; + ~LwIPLock() = default; +#endif }; /** Helper class to request `loop()` to be called as fast as possible.