mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 19:16:06 +00:00
Share task handle between wake.h and lwip_fast_select via main_task.h
This commit is contained in:
@@ -115,12 +115,8 @@ void Application::setup() {
|
||||
#endif
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
// Save main loop task handle for wake_loop_*() FreeRTOS notifications.
|
||||
g_main_task_handle = xTaskGetCurrentTaskHandle();
|
||||
#endif
|
||||
#ifdef USE_LWIP_FAST_SELECT
|
||||
// Initialize fast select: hooks socket monitoring for direct rcvevent reads.
|
||||
esphome_lwip_fast_select_init();
|
||||
// Save main loop task handle for wake_loop_*() / fast select FreeRTOS notifications.
|
||||
esphome_main_task_handle = xTaskGetCurrentTaskHandle();
|
||||
#endif
|
||||
#ifdef USE_HOST
|
||||
// Set up wake socket for waking main loop from tasks (platforms without fast select only)
|
||||
|
||||
@@ -63,11 +63,11 @@
|
||||
//
|
||||
// Shared state and safety rationale:
|
||||
//
|
||||
// s_main_loop_task (TaskHandle_t, 4 bytes):
|
||||
// esphome_main_task_handle (TaskHandle_t, 4 bytes):
|
||||
// Written once by main loop in init(). Read by TCP/IP thread (in callback)
|
||||
// and background tasks (in wake).
|
||||
// Safe: write-once-then-read pattern. Socket hooks may run before init(),
|
||||
// but the NULL check on s_main_loop_task in the callback provides correct
|
||||
// but the NULL check on esphome_main_task_handle in the callback provides correct
|
||||
// degraded behavior — notifications are simply skipped until init() completes.
|
||||
//
|
||||
// s_original_callback (netconn_callback, 4-byte function pointer):
|
||||
@@ -123,6 +123,7 @@
|
||||
#endif
|
||||
|
||||
#include "esphome/core/lwip_fast_select.h"
|
||||
#include "esphome/core/main_task.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -157,8 +158,7 @@ _Static_assert(offsetof(struct lwip_sock, rcvevent) % sizeof(((struct lwip_sock
|
||||
_Static_assert(offsetof(struct lwip_sock, rcvevent) == ESPHOME_LWIP_SOCK_RCVEVENT_OFFSET,
|
||||
"lwip_sock.rcvevent offset changed — update ESPHOME_LWIP_SOCK_RCVEVENT_OFFSET in lwip_fast_select.h");
|
||||
|
||||
// Task handle for the main loop — written once in init(), read from TCP/IP and background tasks.
|
||||
static TaskHandle_t s_main_loop_task = NULL;
|
||||
// Task handle is in main_task.c (esphome_main_task_handle) — shared with wake.h.
|
||||
|
||||
// Saved original event_callback pointer — written once in first hook_socket(), read from TCP/IP task.
|
||||
static netconn_callback s_original_callback = NULL;
|
||||
@@ -177,15 +177,13 @@ static void esphome_socket_event_callback(struct netconn *conn, enum netconn_evt
|
||||
// (rcvevent++ with a NULL pbuf or error in recvmbox), so error conditions
|
||||
// already wake the main loop through the RCVPLUS path.
|
||||
if (evt == NETCONN_EVT_RCVPLUS) {
|
||||
TaskHandle_t task = s_main_loop_task;
|
||||
TaskHandle_t task = esphome_main_task_handle;
|
||||
if (task != NULL) {
|
||||
xTaskNotifyGive(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void esphome_lwip_fast_select_init(void) { s_main_loop_task = xTaskGetCurrentTaskHandle(); }
|
||||
|
||||
// lwip_socket_dbg_get_socket() is a thin wrapper around the static
|
||||
// tryget_socket_unconn_nouse() — a direct array lookup without the refcount
|
||||
// that get_socket()/done_socket() uses. This is safe because:
|
||||
@@ -234,7 +232,7 @@ bool esphome_lwip_set_nodelay(struct lwip_sock *sock, bool enable) {
|
||||
|
||||
// Wake the main loop from another FreeRTOS task. NOT ISR-safe.
|
||||
void esphome_lwip_wake_main_loop(void) {
|
||||
TaskHandle_t task = s_main_loop_task;
|
||||
TaskHandle_t task = esphome_main_task_handle;
|
||||
if (task != NULL) {
|
||||
xTaskNotifyGive(task);
|
||||
}
|
||||
@@ -242,7 +240,7 @@ void esphome_lwip_wake_main_loop(void) {
|
||||
|
||||
// Wake the main loop from an ISR. ISR-safe variant.
|
||||
void IRAM_ATTR esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task_woken) {
|
||||
TaskHandle_t task = s_main_loop_task;
|
||||
TaskHandle_t task = esphome_main_task_handle;
|
||||
if (task != NULL) {
|
||||
vTaskNotifyGiveFromISR(task, (BaseType_t *) px_higher_priority_task_woken);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@ enum { ESPHOME_LWIP_SOCK_RCVEVENT_OFFSET = 8 };
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// Initialize fast select — must be called from the main loop task during setup().
|
||||
/// Saves the current task handle for xTaskNotifyGive() wake notifications.
|
||||
void esphome_lwip_fast_select_init(void);
|
||||
|
||||
/// Look up a LwIP socket struct from a file descriptor.
|
||||
/// Returns NULL if fd is invalid or the socket/netconn is not initialized.
|
||||
/// Use this at registration time to cache the pointer for esphome_lwip_socket_has_data().
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "esphome/core/main_task.h"
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
TaskHandle_t esphome_main_task_handle = NULL;
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
/// Main loop task handle — shared between wake.h (C++) and lwip_fast_select.c (C).
|
||||
/// Set once during Application::setup() via xTaskGetCurrentTaskHandle().
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#elif defined(USE_LIBRETINY)
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern TaskHandle_t esphome_main_task_handle;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -12,12 +12,6 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// === ESP32/LibreTiny — FreeRTOS task handle ===
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
TaskHandle_t g_main_task_handle = nullptr;
|
||||
#endif
|
||||
|
||||
// === ESP32 — IRAM_ATTR entry points ===
|
||||
#ifdef USE_ESP32
|
||||
void IRAM_ATTR wake_loop_isrsafe(int *px_higher_priority_task_woken) {
|
||||
|
||||
+12
-24
@@ -8,13 +8,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
#ifdef USE_ESP32
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#else
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#endif
|
||||
#include "esphome/core/main_task.h"
|
||||
#endif
|
||||
#ifdef USE_ESP8266
|
||||
#include <coredecls.h>
|
||||
@@ -31,41 +25,35 @@ namespace esphome {
|
||||
extern volatile bool g_main_loop_woke;
|
||||
#endif
|
||||
|
||||
// === ESP32/LibreTiny — FreeRTOS task handle for wake notifications ===
|
||||
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
extern TaskHandle_t g_main_task_handle;
|
||||
#endif
|
||||
|
||||
// === ESP32 ===
|
||||
#if defined(USE_ESP32)
|
||||
|
||||
/// Inline impl — ISR callers inline this into IRAM.
|
||||
inline void ESPHOME_ALWAYS_INLINE wake_loop_isrsafe_inline_(int *px_higher_priority_task_woken) {
|
||||
if (g_main_task_handle != nullptr)
|
||||
vTaskNotifyGiveFromISR(g_main_task_handle, (BaseType_t *) px_higher_priority_task_woken);
|
||||
if (esphome_main_task_handle != nullptr)
|
||||
vTaskNotifyGiveFromISR(esphome_main_task_handle, (BaseType_t *) px_higher_priority_task_woken);
|
||||
}
|
||||
/// IRAM_ATTR entry point — defined in wake.cpp.
|
||||
void wake_loop_isrsafe(int *px_higher_priority_task_woken);
|
||||
|
||||
/// Inline impl — ISR callers inline this into IRAM. Uses xPortInIsrContext() to pick safe API.
|
||||
inline void ESPHOME_ALWAYS_INLINE wake_loop_any_context_inline_() {
|
||||
if (g_main_task_handle == nullptr)
|
||||
if (esphome_main_task_handle == nullptr)
|
||||
return;
|
||||
if (xPortInIsrContext()) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR(g_main_task_handle, &xHigherPriorityTaskWoken);
|
||||
vTaskNotifyGiveFromISR(esphome_main_task_handle, &xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
} else {
|
||||
xTaskNotifyGive(g_main_task_handle);
|
||||
xTaskNotifyGive(esphome_main_task_handle);
|
||||
}
|
||||
}
|
||||
/// IRAM_ATTR entry point — defined in wake.cpp.
|
||||
void wake_loop_any_context();
|
||||
|
||||
inline void wake_loop_threadsafe() {
|
||||
if (g_main_task_handle != nullptr)
|
||||
xTaskNotifyGive(g_main_task_handle);
|
||||
if (esphome_main_task_handle != nullptr)
|
||||
xTaskNotifyGive(esphome_main_task_handle);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
@@ -82,13 +70,13 @@ inline void wakeable_delay(uint32_t ms) {
|
||||
#elif defined(USE_LIBRETINY)
|
||||
|
||||
inline void wake_loop_any_context() {
|
||||
if (g_main_task_handle != nullptr)
|
||||
xTaskNotifyGive(g_main_task_handle);
|
||||
if (esphome_main_task_handle != nullptr)
|
||||
xTaskNotifyGive(esphome_main_task_handle);
|
||||
}
|
||||
|
||||
inline void wake_loop_threadsafe() {
|
||||
if (g_main_task_handle != nullptr)
|
||||
xTaskNotifyGive(g_main_task_handle);
|
||||
if (esphome_main_task_handle != nullptr)
|
||||
xTaskNotifyGive(esphome_main_task_handle);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
Reference in New Issue
Block a user