mirror of
https://github.com/esphome/esphome.git
synced 2026-05-28 13:37:24 +08:00
[usb_cdc_acm] Fix EventPool/LockFreeQueue sizing off-by-one (#14894)
This commit is contained in:
@@ -26,16 +26,13 @@ void USBCDCACMInstance::queue_line_state_event(bool dtr, bool rts) {
|
|||||||
event->data.line_state.dtr = dtr;
|
event->data.line_state.dtr = dtr;
|
||||||
event->data.line_state.rts = rts;
|
event->data.line_state.rts = rts;
|
||||||
|
|
||||||
if (!this->event_queue_.push(event)) {
|
// Push always succeeds: pool is sized to queue capacity (SIZE-1), so if
|
||||||
ESP_LOGW(TAG, "Event queue full, line state event dropped (itf=%d)", this->itf_);
|
// allocate() returned non-null, the queue cannot be full.
|
||||||
// Return event to pool since we couldn't queue it
|
this->event_queue_.push(event);
|
||||||
this->event_pool_.release(event);
|
|
||||||
} else {
|
|
||||||
// Wake main loop immediately to process event
|
|
||||||
#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
|
#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
|
||||||
App.wake_loop_threadsafe();
|
App.wake_loop_threadsafe();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBCDCACMInstance::queue_line_coding_event(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity,
|
void USBCDCACMInstance::queue_line_coding_event(uint32_t bit_rate, uint8_t stop_bits, uint8_t parity,
|
||||||
@@ -53,16 +50,13 @@ void USBCDCACMInstance::queue_line_coding_event(uint32_t bit_rate, uint8_t stop_
|
|||||||
event->data.line_coding.parity = parity;
|
event->data.line_coding.parity = parity;
|
||||||
event->data.line_coding.data_bits = data_bits;
|
event->data.line_coding.data_bits = data_bits;
|
||||||
|
|
||||||
if (!this->event_queue_.push(event)) {
|
// Push always succeeds: pool is sized to queue capacity (SIZE-1), so if
|
||||||
ESP_LOGW(TAG, "Event queue full, line coding event dropped (itf=%d)", this->itf_);
|
// allocate() returned non-null, the queue cannot be full.
|
||||||
// Return event to pool since we couldn't queue it
|
this->event_queue_.push(event);
|
||||||
this->event_pool_.release(event);
|
|
||||||
} else {
|
|
||||||
// Wake main loop immediately to process event
|
|
||||||
#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
|
#if defined(USE_SOCKET_SELECT_SUPPORT) && defined(USE_WAKE_LOOP_THREADSAFE)
|
||||||
App.wake_loop_threadsafe();
|
App.wake_loop_threadsafe();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBCDCACMInstance::process_events_() {
|
void USBCDCACMInstance::process_events_() {
|
||||||
|
|||||||
@@ -102,7 +102,11 @@ class USBCDCACMInstance : public uart::UARTComponent, public Parented<USBCDCACMC
|
|||||||
LineStateCallback line_state_callback_{nullptr};
|
LineStateCallback line_state_callback_{nullptr};
|
||||||
|
|
||||||
// Lock-free queue and event pool for cross-task event passing
|
// Lock-free queue and event pool for cross-task event passing
|
||||||
EventPool<CDCEvent, EVENT_QUEUE_SIZE> event_pool_;
|
// Pool sized to queue capacity (SIZE-1) because LockFreeQueue<T,N> is a ring
|
||||||
|
// buffer that holds N-1 elements. This guarantees allocate() returns nullptr
|
||||||
|
// before push() can fail, preventing both a pool slot leak and an SPSC
|
||||||
|
// violation on the pool's internal free list.
|
||||||
|
EventPool<CDCEvent, EVENT_QUEUE_SIZE - 1> event_pool_;
|
||||||
LockFreeQueue<CDCEvent, EVENT_QUEUE_SIZE> event_queue_;
|
LockFreeQueue<CDCEvent, EVENT_QUEUE_SIZE> event_queue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user