mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00:00 
			
		
		
		
	Merge branch 'loop_done_enable_isr' into binary_sensor_gpio_polling
This commit is contained in:
		| @@ -163,15 +163,15 @@ void Component::enable_loop() { | ||||
|     App.enable_component_loop_(this); | ||||
|   } | ||||
| } | ||||
| void IRAM_ATTR HOT Component::enable_loop_soon_from_isr() { | ||||
|   // This method is ISR-safe because: | ||||
| void IRAM_ATTR HOT Component::enable_loop_soon_any_context() { | ||||
|   // This method is thread and ISR-safe because: | ||||
|   // 1. Only performs simple assignments to volatile variables (atomic on all platforms) | ||||
|   // 2. No read-modify-write operations that could be interrupted | ||||
|   // 3. No memory allocation, object construction, or function calls | ||||
|   // 4. IRAM_ATTR ensures code is in IRAM, not flash (required for ISR execution) | ||||
|   // 5. Components are never destroyed, so no use-after-free concerns | ||||
|   // 6. App is guaranteed to be initialized before any ISR could fire | ||||
|   // 7. Multiple ISR calls are safe - just sets the same flags to true | ||||
|   // 7. Multiple ISR/thread calls are safe - just sets the same flags to true | ||||
|   // 8. Race condition with main loop is handled by clearing flag before processing | ||||
|   this->pending_enable_loop_ = true; | ||||
|   App.has_pending_enable_loop_requests_ = true; | ||||
|   | ||||
| @@ -171,15 +171,15 @@ class Component { | ||||
|    */ | ||||
|   void enable_loop(); | ||||
|  | ||||
|   /** ISR-safe version of enable_loop() that can be called from interrupt context. | ||||
|   /** Thread and ISR-safe version of enable_loop() that can be called from any context. | ||||
|    * | ||||
|    * This method defers the actual enable via enable_pending_loops_ to the main loop, | ||||
|    * making it safe to call from ISR handlers, timer callbacks, or other | ||||
|    * interrupt contexts. | ||||
|    * making it safe to call from ISR handlers, timer callbacks, other threads, | ||||
|    * or any interrupt context. | ||||
|    * | ||||
|    * @note The actual loop enabling will happen on the next main loop iteration. | ||||
|    * @note Only one pending enable request is tracked per component. | ||||
|    * @note There is no disable_loop_soon_from_isr() on purpose - it would race | ||||
|    * @note There is no disable_loop_soon_any_context() on purpose - it would race | ||||
|    *       against enable calls and synchronization would get too complex | ||||
|    *       to provide a safe version that would work for each component. | ||||
|    * | ||||
| @@ -190,7 +190,7 @@ class Component { | ||||
|    *       disable_loop() in its next ::loop() iteration. Implementations | ||||
|    *       will need to carefully consider all possible race conditions. | ||||
|    */ | ||||
|   void enable_loop_soon_from_isr(); | ||||
|   void enable_loop_soon_any_context(); | ||||
|  | ||||
|   bool is_failed() const; | ||||
|  | ||||
| @@ -363,7 +363,7 @@ class Component { | ||||
|   /// Bit 3: STATUS_LED_ERROR | ||||
|   /// Bits 4-7: Unused - reserved for future expansion (50% of the bits are free) | ||||
|   uint8_t component_state_{0x00}; | ||||
|   volatile bool pending_enable_loop_{false};  ///< ISR-safe flag for enable_loop_soon_from_isr | ||||
|   volatile bool pending_enable_loop_{false};  ///< ISR-safe flag for enable_loop_soon_any_context | ||||
| }; | ||||
|  | ||||
| /** This class simplifies creating components that periodically check a state. | ||||
|   | ||||
| @@ -67,10 +67,10 @@ void IRAM_ATTR LoopTestISRComponent::simulate_isr_enable() { | ||||
|  | ||||
|   this->isr_call_count_++; | ||||
|  | ||||
|   // Call enable_loop_soon_from_isr multiple times to test that it's safe | ||||
|   this->enable_loop_soon_from_isr(); | ||||
|   this->enable_loop_soon_from_isr();  // Test multiple calls | ||||
|   this->enable_loop_soon_from_isr();  // Should be idempotent | ||||
|   // Call enable_loop_soon_any_context multiple times to test that it's safe | ||||
|   this->enable_loop_soon_any_context(); | ||||
|   this->enable_loop_soon_any_context();  // Test multiple calls | ||||
|   this->enable_loop_soon_any_context();  // Should be idempotent | ||||
|  | ||||
|   // Note: In a real ISR, we cannot use ESP_LOG* macros as they're not ISR-safe | ||||
|   // For testing, we'll track the call count and log it from the main loop | ||||
|   | ||||
| @@ -14,7 +14,7 @@ class LoopTestISRComponent : public Component { | ||||
|   void setup() override; | ||||
|   void loop() override; | ||||
|  | ||||
|   // Simulates an ISR calling enable_loop_soon_from_isr | ||||
|   // Simulates an ISR calling enable_loop_soon_any_context | ||||
|   void simulate_isr_enable(); | ||||
|  | ||||
|   float get_setup_priority() const override { return setup_priority::DATA; } | ||||
|   | ||||
| @@ -35,7 +35,7 @@ loop_test_component: | ||||
|       test_redundant_operations: true | ||||
|       disable_after: 10 | ||||
|  | ||||
|   # ISR test component that uses enable_loop_soon_from_isr | ||||
|   # ISR test component that uses enable_loop_soon_any_context | ||||
|   isr_components: | ||||
|     - id: isr_test | ||||
|       name: "isr_test" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user