mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
Switch to atomic uint8_t flag, fix race condition
Replace atomic counter with a simple flag to avoid underflow race where consumer could decrement before producer increments. Use uint8_t instead of bool to avoid GCC Xtensa indirect call issue. Clear flag before draining — if a new event arrives between clear and xQueueReceive, the flag is set again and caught next iteration.
This commit is contained in:
@@ -49,9 +49,11 @@ static const char *const TAG = "wifi_esp32";
|
|||||||
|
|
||||||
static EventGroupHandle_t s_wifi_event_group; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
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 QueueHandle_t s_event_queue; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
// Fast-path counter to skip xQueueReceive kernel call when queue is empty.
|
// Fast-path flag to skip xQueueReceive kernel call when queue is empty.
|
||||||
// Incremented from event handler (ISR-safe context), read from main loop.
|
// Set from ESP-IDF event loop handler (task context), cleared from main loop.
|
||||||
static std::atomic<uint32_t> s_event_count{0}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
// std::atomic<bool> is avoided because GCC on Xtensa generates indirect function
|
||||||
|
// calls for atomic bool operations instead of inlining them.
|
||||||
|
static std::atomic<uint8_t> s_event_pending{0}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
static esp_netif_t *s_sta_netif = nullptr; // 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
|
#ifdef USE_WIFI_AP
|
||||||
static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
static esp_netif_t *s_ap_netif = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
@@ -143,7 +145,7 @@ void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, voi
|
|||||||
if (xQueueSend(s_event_queue, &to_send, 0L) != pdPASS) {
|
if (xQueueSend(s_event_queue, &to_send, 0L) != pdPASS) {
|
||||||
delete to_send; // NOLINT(cppcoreguidelines-owning-memory)
|
delete to_send; // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
} else {
|
} else {
|
||||||
s_event_count.fetch_add(1, std::memory_order_release);
|
s_event_pending.store(1, std::memory_order_release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,16 +734,20 @@ const char *get_disconnect_reason_str(uint8_t reason) {
|
|||||||
void WiFiComponent::wifi_loop_() {
|
void WiFiComponent::wifi_loop_() {
|
||||||
// Fast path: skip xQueueReceive kernel call when no events are pending.
|
// Fast path: skip xQueueReceive kernel call when no events are pending.
|
||||||
// The atomic load is much cheaper than entering the FreeRTOS kernel.
|
// The atomic load is much cheaper than entering the FreeRTOS kernel.
|
||||||
if (s_event_count.load(std::memory_order_acquire) == 0)
|
if (s_event_pending.load(std::memory_order_acquire) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Clear flag before draining. If a new event arrives between the clear
|
||||||
|
// and xQueueReceive, the flag will be set again and we'll catch it
|
||||||
|
// next loop iteration. This avoids any counter underflow issues.
|
||||||
|
s_event_pending.store(0, std::memory_order_relaxed);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
IDFWiFiEvent *data;
|
IDFWiFiEvent *data;
|
||||||
if (xQueueReceive(s_event_queue, &data, 0L) != pdTRUE) {
|
if (xQueueReceive(s_event_queue, &data, 0L) != pdTRUE) {
|
||||||
// no event ready
|
// no event ready
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
s_event_count.fetch_sub(1, std::memory_order_relaxed);
|
|
||||||
|
|
||||||
// process event
|
// process event
|
||||||
wifi_process_event_(data);
|
wifi_process_event_(data);
|
||||||
|
|||||||
Reference in New Issue
Block a user