mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +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 { | ||||
|       uint8_t new_app_state = STATUS_LED_WARNING; | ||||
|       this->scheduler.call(millis()); | ||||
|       this->feed_wdt(); | ||||
|       uint32_t now = millis(); | ||||
|  | ||||
|       // Process pending loop enables to handle GPIO interrupts during setup | ||||
|       this->before_loop_tasks_(now); | ||||
|  | ||||
|       for (uint32_t j = 0; j <= i; j++) { | ||||
|         // Update loop_component_start_time_ right before calling each component | ||||
|         this->loop_component_start_time_ = millis(); | ||||
| @@ -81,6 +84,8 @@ void Application::setup() { | ||||
|         this->app_state_ |= new_app_state; | ||||
|         this->feed_wdt(); | ||||
|       } | ||||
|  | ||||
|       this->after_loop_tasks_(); | ||||
|       this->app_state_ = new_app_state; | ||||
|       yield(); | ||||
|     } while (!component->can_proceed()); | ||||
| @@ -100,27 +105,7 @@ void Application::loop() { | ||||
|   // Get the initial loop time at the start | ||||
|   uint32_t last_op_end_time = millis(); | ||||
|  | ||||
|   this->scheduler.call(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; | ||||
|   this->before_loop_tasks_(last_op_end_time); | ||||
|  | ||||
|   for (this->current_loop_index_ = 0; this->current_loop_index_ < this->looping_components_active_end_; | ||||
|        this->current_loop_index_++) { | ||||
| @@ -141,7 +126,7 @@ void Application::loop() { | ||||
|     this->feed_wdt(last_op_end_time); | ||||
|   } | ||||
|  | ||||
|   this->in_loop_ = false; | ||||
|   this->after_loop_tasks_(); | ||||
|   this->app_state_ = new_app_state; | ||||
|  | ||||
| #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 | ||||
| bool Application::register_socket_fd(int fd) { | ||||
|   // 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_pending_loops_(); | ||||
|   void activate_looping_component_(uint16_t index); | ||||
|   void before_loop_tasks_(uint32_t loop_start_time); | ||||
|   void after_loop_tasks_(); | ||||
|  | ||||
|   void feed_wdt_arch_(); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user