Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Add a comment to EventPool documenting that when paired with a
LockFreeQueue<T, N>, the pool should be sized to N-1 (the queue's
actual capacity) to prevent slot leaks and SPSC violations.
LockFreeQueue<T,N> is a ring buffer that holds N-1 elements (one slot
is reserved to distinguish full from empty). With the pool also sized
to N, the Nth allocate() succeeds but push() fails — permanently
leaking one pool slot since the element is never returned.
Size both receive and send pools to N-1 to match queue capacity.
LockFreeQueue<T,N> is a ring buffer that holds N-1 elements (one slot
is reserved to distinguish full from empty). With the pool also sized
to N, the Nth allocate() succeeds but push() fails — permanently
leaking one pool slot since the element is never returned.
Size the pool to N-1 to match queue capacity. This guarantees
allocate() returns nullptr before push() can fail.
The ESP-IDF MQTT client dispatches events from its own task, which
pushed to a std::queue while the main loop popped from it. std::queue
is not thread-safe; concurrent access can corrupt its internal state.
Replace with EventPool + LockFreeQueue (SPSC ring buffer) already
used elsewhere in the codebase. The pool is sized to queue capacity
(SIZE-1) so allocate() fails before push() can, which prevents both
a slot leak and an SPSC violation on the pool's free list.
Also rename the outbound pool from mqtt_event_pool_ to
mqtt_outbound_pool_ to avoid confusion with the new inbound pool.
On ESPHOME_THREAD_SINGLE there are no concurrent writers, so
to_add_empty_() checks to_add_.empty() directly. The counter
field and its increment/clear operations are compiled out.
cleanup_() was computing items_.size() on every call even on the
fast path where nothing was removed. All callers only check if
items remain (== 0), so return bool and use items_.empty() instead.
The mutex already provides all necessary memory ordering for the
counter operations. acquire/release fences on the fast-path reads
were causing unnecessary cache flushes, regressing
Scheduler_NextScheduleIn by ~10%.