diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index d8b3db9667..9bf8192ee1 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -39,6 +39,7 @@ #include "esphome/core/application.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" +#include "esphome/core/lock_free_queue.h" #include "esphome/core/log.h" #include "esphome/core/util.h" @@ -47,8 +48,11 @@ namespace esphome::wifi { static const char *const TAG = "wifi_esp32"; static EventGroupHandle_t s_wifi_event_group; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static QueueHandle_t s_event_queue; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static esp_netif_t *s_sta_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +// Lock-free SPSC queue replaces FreeRTOS xQueue to avoid kernel spinlock +// overhead on every loop iteration. WiFi events are rare so 64 slots is plenty. +// 65 slots = 64 usable (ring buffer reserves one slot to distinguish full from empty) +static LockFreeQueue s_event_queue; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +static esp_netif_t *s_sta_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) #ifdef USE_WIFI_AP static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) #endif // USE_WIFI_AP @@ -132,11 +136,10 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi return; } - // copy to heap to keep queue object small + // copy to heap — WiFi events are rare so heap alloc is fine auto *to_send = new IDFWiFiEvent; // NOLINT(cppcoreguidelines-owning-memory) memcpy(to_send, &event, sizeof(IDFWiFiEvent)); - // don't block, we may miss events but the core can handle that - if (xQueueSend(s_event_queue, &to_send, 0L) != pdPASS) { + if (!s_event_queue.push(to_send)) { delete to_send; // NOLINT(cppcoreguidelines-owning-memory) } } @@ -157,12 +160,6 @@ void WiFiComponent::wifi_pre_setup_() { ESP_LOGE(TAG, "xEventGroupCreate failed"); return; } - // NOLINTNEXTLINE(bugprone-sizeof-expression) - s_event_queue = xQueueCreate(64, sizeof(IDFWiFiEvent *)); - if (s_event_queue == nullptr) { - ESP_LOGE(TAG, "xQueueCreate failed"); - return; - } err = esp_event_loop_create_default(); if (err != ERR_OK) { ESP_LOGE(TAG, "esp_event_loop_create_default failed: %s", esp_err_to_name(err)); @@ -724,16 +721,9 @@ const char *get_disconnect_reason_str(uint8_t reason) { } void WiFiComponent::wifi_loop_() { - while (true) { - IDFWiFiEvent *data; - if (xQueueReceive(s_event_queue, &data, 0L) != pdTRUE) { - // no event ready - break; - } - - // process event + IDFWiFiEvent *data; + while ((data = s_event_queue.pop()) != nullptr) { wifi_process_event_(data); - delete data; // NOLINT(cppcoreguidelines-owning-memory) } }