mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[core] Process pending loop enables during setup blocking phase (#9787)
This commit is contained in:
		| @@ -71,8 +71,11 @@ void Application::setup() { | |||||||
|  |  | ||||||
|     do { |     do { | ||||||
|       uint8_t new_app_state = STATUS_LED_WARNING; |       uint8_t new_app_state = STATUS_LED_WARNING; | ||||||
|       this->scheduler.call(millis()); |       uint32_t now = millis(); | ||||||
|       this->feed_wdt(); |  | ||||||
|  |       // Process pending loop enables to handle GPIO interrupts during setup | ||||||
|  |       this->before_loop_tasks_(now); | ||||||
|  |  | ||||||
|       for (uint32_t j = 0; j <= i; j++) { |       for (uint32_t j = 0; j <= i; j++) { | ||||||
|         // Update loop_component_start_time_ right before calling each component |         // Update loop_component_start_time_ right before calling each component | ||||||
|         this->loop_component_start_time_ = millis(); |         this->loop_component_start_time_ = millis(); | ||||||
| @@ -81,6 +84,8 @@ void Application::setup() { | |||||||
|         this->app_state_ |= new_app_state; |         this->app_state_ |= new_app_state; | ||||||
|         this->feed_wdt(); |         this->feed_wdt(); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       this->after_loop_tasks_(); | ||||||
|       this->app_state_ = new_app_state; |       this->app_state_ = new_app_state; | ||||||
|       yield(); |       yield(); | ||||||
|     } while (!component->can_proceed()); |     } while (!component->can_proceed()); | ||||||
| @@ -100,27 +105,7 @@ void Application::loop() { | |||||||
|   // Get the initial loop time at the start |   // Get the initial loop time at the start | ||||||
|   uint32_t last_op_end_time = millis(); |   uint32_t last_op_end_time = millis(); | ||||||
|  |  | ||||||
|   this->scheduler.call(last_op_end_time); |   this->before_loop_tasks_(last_op_end_time); | ||||||
|  |  | ||||||
|   // Feed WDT with time |  | ||||||
|   this->feed_wdt(last_op_end_time); |  | ||||||
|  |  | ||||||
|   // Process any pending enable_loop requests from ISRs |  | ||||||
|   // This must be done before marking in_loop_ = true to avoid race conditions |  | ||||||
|   if (this->has_pending_enable_loop_requests_) { |  | ||||||
|     // Clear flag BEFORE processing to avoid race condition |  | ||||||
|     // If ISR sets it during processing, we'll catch it next loop iteration |  | ||||||
|     // This is safe because: |  | ||||||
|     // 1. Each component has its own pending_enable_loop_ flag that we check |  | ||||||
|     // 2. If we can't process a component (wrong state), enable_pending_loops_() |  | ||||||
|     //    will set this flag back to true |  | ||||||
|     // 3. Any new ISR requests during processing will set the flag again |  | ||||||
|     this->has_pending_enable_loop_requests_ = false; |  | ||||||
|     this->enable_pending_loops_(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Mark that we're in the loop for safe reentrant modifications |  | ||||||
|   this->in_loop_ = true; |  | ||||||
|  |  | ||||||
|   for (this->current_loop_index_ = 0; this->current_loop_index_ < this->looping_components_active_end_; |   for (this->current_loop_index_ = 0; this->current_loop_index_ < this->looping_components_active_end_; | ||||||
|        this->current_loop_index_++) { |        this->current_loop_index_++) { | ||||||
| @@ -141,7 +126,7 @@ void Application::loop() { | |||||||
|     this->feed_wdt(last_op_end_time); |     this->feed_wdt(last_op_end_time); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   this->in_loop_ = false; |   this->after_loop_tasks_(); | ||||||
|   this->app_state_ = new_app_state; |   this->app_state_ = new_app_state; | ||||||
|  |  | ||||||
| #ifdef USE_RUNTIME_STATS | #ifdef USE_RUNTIME_STATS | ||||||
| @@ -411,6 +396,36 @@ void Application::enable_pending_loops_() { | |||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void Application::before_loop_tasks_(uint32_t loop_start_time) { | ||||||
|  |   // Process scheduled tasks | ||||||
|  |   this->scheduler.call(loop_start_time); | ||||||
|  |  | ||||||
|  |   // Feed the watchdog timer | ||||||
|  |   this->feed_wdt(loop_start_time); | ||||||
|  |  | ||||||
|  |   // Process any pending enable_loop requests from ISRs | ||||||
|  |   // This must be done before marking in_loop_ = true to avoid race conditions | ||||||
|  |   if (this->has_pending_enable_loop_requests_) { | ||||||
|  |     // Clear flag BEFORE processing to avoid race condition | ||||||
|  |     // If ISR sets it during processing, we'll catch it next loop iteration | ||||||
|  |     // This is safe because: | ||||||
|  |     // 1. Each component has its own pending_enable_loop_ flag that we check | ||||||
|  |     // 2. If we can't process a component (wrong state), enable_pending_loops_() | ||||||
|  |     //    will set this flag back to true | ||||||
|  |     // 3. Any new ISR requests during processing will set the flag again | ||||||
|  |     this->has_pending_enable_loop_requests_ = false; | ||||||
|  |     this->enable_pending_loops_(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Mark that we're in the loop for safe reentrant modifications | ||||||
|  |   this->in_loop_ = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Application::after_loop_tasks_() { | ||||||
|  |   // Clear the in_loop_ flag to indicate we're done processing components | ||||||
|  |   this->in_loop_ = false; | ||||||
|  | } | ||||||
|  |  | ||||||
| #ifdef USE_SOCKET_SELECT_SUPPORT | #ifdef USE_SOCKET_SELECT_SUPPORT | ||||||
| bool Application::register_socket_fd(int fd) { | bool Application::register_socket_fd(int fd) { | ||||||
|   // WARNING: This function is NOT thread-safe and must only be called from the main loop |   // WARNING: This function is NOT thread-safe and must only be called from the main loop | ||||||
|   | |||||||
| @@ -512,6 +512,8 @@ class Application { | |||||||
|   void enable_component_loop_(Component *component); |   void enable_component_loop_(Component *component); | ||||||
|   void enable_pending_loops_(); |   void enable_pending_loops_(); | ||||||
|   void activate_looping_component_(uint16_t index); |   void activate_looping_component_(uint16_t index); | ||||||
|  |   void before_loop_tasks_(uint32_t loop_start_time); | ||||||
|  |   void after_loop_tasks_(); | ||||||
|  |  | ||||||
|   void feed_wdt_arch_(); |   void feed_wdt_arch_(); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user