From fb998468b52bce596726899ce4e8e775e69877ec Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 28 Feb 2026 15:01:12 -1000 Subject: [PATCH 1/3] Fix comment about function calls and initialize ipsr - Update ISR safety comment: point 3 now reflects that wake_loop_any_context() is called (ISR-safe) - Initialize ipsr = 0 as safety net before inline asm --- esphome/core/component.cpp | 2 +- esphome/core/lwip_fast_select.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index c8875f07054..0154bd67351 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -315,7 +315,7 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() { // This method is thread and ISR-safe because: // 1. Only performs simple assignments to volatile variables (atomic on all platforms) // 2. No read-modify-write operations that could be interrupted - // 3. No memory allocation, object construction, or function calls + // 3. No memory allocation or object construction; the only call (wake_loop_any_context) is ISR-safe // 4. IRAM_ATTR ensures code is in IRAM, not flash (required for ISR execution) // 5. Components are never destroyed, so no use-after-free concerns // 6. App is guaranteed to be initialized before any ISR could fire diff --git a/esphome/core/lwip_fast_select.c b/esphome/core/lwip_fast_select.c index 370638a8e08..63a58b71e6b 100644 --- a/esphome/core/lwip_fast_select.c +++ b/esphome/core/lwip_fast_select.c @@ -247,7 +247,7 @@ void IRAM_ATTR esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task // Avoids depending on CMSIS __get_IPSR() which may not be declared/available // in all LibreTiny chip family toolchains (e.g. beken-72xx). static inline uint32_t esphome_get_ipsr(void) { - uint32_t ipsr; + uint32_t ipsr = 0; __asm volatile("mrs %0, ipsr" : "=r"(ipsr)); return ipsr; } From 9f7508e50be4efb6125550d32ac181ad95f8b889 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 28 Feb 2026 15:01:52 -1000 Subject: [PATCH 2/3] Add IRAM_ATTR to esphome_get_ipsr for future-proofing Currently a no-op on LibreTiny but ensures the function stays in IRAM if the platform later defines IRAM_ATTR. --- esphome/core/lwip_fast_select.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/lwip_fast_select.c b/esphome/core/lwip_fast_select.c index 63a58b71e6b..a3cc6ab8fe1 100644 --- a/esphome/core/lwip_fast_select.c +++ b/esphome/core/lwip_fast_select.c @@ -246,7 +246,7 @@ void IRAM_ATTR esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task // Read the ARM Cortex-M IPSR register directly via inline asm. // Avoids depending on CMSIS __get_IPSR() which may not be declared/available // in all LibreTiny chip family toolchains (e.g. beken-72xx). -static inline uint32_t esphome_get_ipsr(void) { +static inline IRAM_ATTR uint32_t esphome_get_ipsr(void) { uint32_t ipsr = 0; __asm volatile("mrs %0, ipsr" : "=r"(ipsr)); return ipsr; From 54126fef369d6c23112bb7adf4699f4cd4dde4e3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 28 Feb 2026 15:08:30 -1000 Subject: [PATCH 3/3] Only set USE_LWIP_FAST_SELECT when select support is available The fast select code paths and wake_loop_any_context() require USE_SOCKET_SELECT_SUPPORT. Gate USE_LWIP_FAST_SELECT on not using lwip_tcp implementation which does not provide select() support. --- esphome/components/socket/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/components/socket/__init__.py b/esphome/components/socket/__init__.py index a1e5d16036f..08cf3ea33c3 100644 --- a/esphome/components/socket/__init__.py +++ b/esphome/components/socket/__init__.py @@ -189,8 +189,9 @@ async def to_code(config): cg.add_define("USE_SOCKET_IMPL_BSD_SOCKETS") cg.add_define("USE_SOCKET_SELECT_SUPPORT") # ESP32 and LibreTiny both have LwIP >= 2.1.3 with lwip_socket_dbg_get_socket() - # and FreeRTOS task notifications — enable fast select to bypass lwip_select() - if CORE.is_esp32 or CORE.is_libretiny: + # and FreeRTOS task notifications — enable fast select to bypass lwip_select(). + # Only when not using lwip_tcp, which does not provide select() support. + if (CORE.is_esp32 or CORE.is_libretiny) and impl != IMPLEMENTATION_LWIP_TCP: cg.add_build_flag("-DUSE_LWIP_FAST_SELECT")