mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	Merge branch 'extract_helpers' into integration
This commit is contained in:
		| @@ -1,6 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|  | ||||
| #include <atomic> | ||||
| #include <cstddef> | ||||
| @@ -11,12 +11,18 @@ namespace esphome { | ||||
|  | ||||
| // Event Pool - On-demand pool of objects to avoid heap fragmentation | ||||
| // Events are allocated on first use and reused thereafter, growing to peak usage | ||||
| // @tparam T The type of objects managed by the pool (must have a clear() method) | ||||
| // @tparam SIZE The maximum number of objects in the pool (1-255, limited by uint8_t) | ||||
| template<class T, uint8_t SIZE> class EventPool { | ||||
|  public: | ||||
|   EventPool() : total_created_(0) {} | ||||
|  | ||||
|   ~EventPool() { | ||||
|     // Clean up any remaining events in the free list | ||||
|     // IMPORTANT: This destructor assumes no concurrent access. The EventPool must not | ||||
|     // be destroyed while any thread might still call allocate() or release(). | ||||
|     // In practice, this is typically ensured by destroying the pool only during | ||||
|     // component shutdown when all producer/consumer threads have been stopped. | ||||
|     T *event; | ||||
|     RAMAllocator<T> allocator(RAMAllocator<T>::ALLOC_INTERNAL); | ||||
|     while ((event = this->free_list_.pop()) != nullptr) { | ||||
| @@ -67,9 +73,9 @@ template<class T, uint8_t SIZE> class EventPool { | ||||
|  | ||||
|  private: | ||||
|   LockFreeQueue<T, SIZE> free_list_;  // Free events ready for reuse | ||||
|   uint8_t total_created_;             // Total events created (high water mark) | ||||
|   uint8_t total_created_;             // Total events created (high water mark, max 255) | ||||
| }; | ||||
|  | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
| #endif  // defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|   | ||||
| @@ -1,11 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #ifdef USE_ESP32 | ||||
| #if defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|  | ||||
| #include <atomic> | ||||
| #include <cstddef> | ||||
|  | ||||
| #if defined(USE_ESP32) | ||||
| #include <freertos/FreeRTOS.h> | ||||
| #include <freertos/task.h> | ||||
| #elif defined(USE_LIBRETINY) | ||||
| #include <FreeRTOS.h> | ||||
| #include <task.h> | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Lock-free queue for single-producer single-consumer scenarios. | ||||
| @@ -13,9 +19,14 @@ | ||||
|  * blocking each other. | ||||
|  * | ||||
|  * This is a Single-Producer Single-Consumer (SPSC) lock-free ring buffer. | ||||
|  * Available on platforms with FreeRTOS support (ESP32, LibreTiny). | ||||
|  * | ||||
|  * Common use cases: | ||||
|  * - BLE events: BLE task produces, main loop consumes | ||||
|  * - MQTT messages: main task produces, MQTT thread consumes | ||||
|  * | ||||
|  * @tparam T The type of elements stored in the queue (must be a pointer type) | ||||
|  * @tparam SIZE The maximum number of elements (1-255, limited by uint8_t indices) | ||||
|  */ | ||||
|  | ||||
| namespace esphome { | ||||
| @@ -56,6 +67,9 @@ template<class T, uint8_t SIZE> class LockFreeQueue { | ||||
|         uint8_t head_after = head_.load(std::memory_order_acquire); | ||||
|         if (head_after == current_tail) { | ||||
|           // Consumer just caught up to where tail was - might go to sleep, must notify | ||||
|           // Note: There's a benign race here - between reading head_after and calling | ||||
|           // xTaskNotifyGive(), the consumer could advance further. This would result | ||||
|           // in an unnecessary wake-up, but is harmless and extremely rare in practice. | ||||
|           xTaskNotifyGive(task_to_notify_); | ||||
|         } | ||||
|         // Otherwise: consumer is still behind, no need to notify | ||||
| @@ -104,6 +118,8 @@ template<class T, uint8_t SIZE> class LockFreeQueue { | ||||
|   // Atomic: written by producer (push/increment), read+reset by consumer (get_and_reset) | ||||
|   std::atomic<uint16_t> dropped_count_;  // 65535 max - more than enough for drop tracking | ||||
|   // Atomic: written by consumer (pop), read by producer (push) to check if full | ||||
|   // Using uint8_t limits queue size to 255 elements but saves memory and ensures | ||||
|   // atomic operations are efficient on all platforms | ||||
|   std::atomic<uint8_t> head_; | ||||
|   // Atomic: written by producer (push), read by consumer (pop) to check if empty | ||||
|   std::atomic<uint8_t> tail_; | ||||
| @@ -113,4 +129,4 @@ template<class T, uint8_t SIZE> class LockFreeQueue { | ||||
|  | ||||
| }  // namespace esphome | ||||
|  | ||||
| #endif | ||||
| #endif  // defined(USE_ESP32) || defined(USE_LIBRETINY) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user