mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Always perform select() when loop duration exceeds interval (#9058)
This commit is contained in:
		| @@ -117,7 +117,9 @@ void Application::loop() { | |||||||
|   // Use the last component's end time instead of calling millis() again |   // Use the last component's end time instead of calling millis() again | ||||||
|   auto elapsed = last_op_end_time - this->last_loop_; |   auto elapsed = last_op_end_time - this->last_loop_; | ||||||
|   if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) { |   if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) { | ||||||
|     yield(); |     // Even if we overran the loop interval, we still need to select() | ||||||
|  |     // to know if any sockets have data ready | ||||||
|  |     this->yield_with_select_(0); | ||||||
|   } else { |   } else { | ||||||
|     uint32_t delay_time = this->loop_interval_ - elapsed; |     uint32_t delay_time = this->loop_interval_ - elapsed; | ||||||
|     uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time); |     uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time); | ||||||
| @@ -126,7 +128,7 @@ void Application::loop() { | |||||||
|     next_schedule = std::max(next_schedule, delay_time / 2); |     next_schedule = std::max(next_schedule, delay_time / 2); | ||||||
|     delay_time = std::min(next_schedule, delay_time); |     delay_time = std::min(next_schedule, delay_time); | ||||||
|  |  | ||||||
|     this->delay_with_select_(delay_time); |     this->yield_with_select_(delay_time); | ||||||
|   } |   } | ||||||
|   this->last_loop_ = last_op_end_time; |   this->last_loop_ = last_op_end_time; | ||||||
|  |  | ||||||
| @@ -215,7 +217,7 @@ void Application::teardown_components(uint32_t timeout_ms) { | |||||||
|  |  | ||||||
|     // Give some time for I/O operations if components are still pending |     // Give some time for I/O operations if components are still pending | ||||||
|     if (!pending_components.empty()) { |     if (!pending_components.empty()) { | ||||||
|       this->delay_with_select_(1); |       this->yield_with_select_(1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Update time for next iteration |     // Update time for next iteration | ||||||
| @@ -293,8 +295,6 @@ bool Application::is_socket_ready(int fd) const { | |||||||
|   // This function is thread-safe for reading the result of select() |   // This function is thread-safe for reading the result of select() | ||||||
|   // However, it should only be called after select() has been executed in the main loop |   // However, it should only be called after select() has been executed in the main loop | ||||||
|   // The read_fds_ is only modified by select() in the main loop |   // The read_fds_ is only modified by select() in the main loop | ||||||
|   if (HighFrequencyLoopRequester::is_high_frequency()) |  | ||||||
|     return true;  // fd sets via select are not updated in high frequency looping - so force true fallback behavior |  | ||||||
|   if (fd < 0 || fd >= FD_SETSIZE) |   if (fd < 0 || fd >= FD_SETSIZE) | ||||||
|     return false; |     return false; | ||||||
|  |  | ||||||
| @@ -302,7 +302,9 @@ bool Application::is_socket_ready(int fd) const { | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| void Application::delay_with_select_(uint32_t delay_ms) { | void Application::yield_with_select_(uint32_t delay_ms) { | ||||||
|  |   // Delay while monitoring sockets. When delay_ms is 0, always yield() to ensure other tasks run | ||||||
|  |   // since select() with 0 timeout only polls without yielding. | ||||||
| #ifdef USE_SOCKET_SELECT_SUPPORT | #ifdef USE_SOCKET_SELECT_SUPPORT | ||||||
|   if (!this->socket_fds_.empty()) { |   if (!this->socket_fds_.empty()) { | ||||||
|     // Update fd_set if socket list has changed |     // Update fd_set if socket list has changed | ||||||
| @@ -340,6 +342,10 @@ void Application::delay_with_select_(uint32_t delay_ms) { | |||||||
|       ESP_LOGW(TAG, "select() failed with errno %d", errno); |       ESP_LOGW(TAG, "select() failed with errno %d", errno); | ||||||
|       delay(delay_ms); |       delay(delay_ms); | ||||||
|     } |     } | ||||||
|  |     // When delay_ms is 0, we need to yield since select(0) doesn't yield | ||||||
|  |     if (delay_ms == 0) { | ||||||
|  |       yield(); | ||||||
|  |     } | ||||||
|   } else { |   } else { | ||||||
|     // No sockets registered, use regular delay |     // No sockets registered, use regular delay | ||||||
|     delay(delay_ms); |     delay(delay_ms); | ||||||
|   | |||||||
| @@ -575,7 +575,7 @@ class Application { | |||||||
|   void feed_wdt_arch_(); |   void feed_wdt_arch_(); | ||||||
|  |  | ||||||
|   /// Perform a delay while also monitoring socket file descriptors for readiness |   /// Perform a delay while also monitoring socket file descriptors for readiness | ||||||
|   void delay_with_select_(uint32_t delay_ms); |   void yield_with_select_(uint32_t delay_ms); | ||||||
|  |  | ||||||
|   std::vector<Component *> components_{}; |   std::vector<Component *> components_{}; | ||||||
|   std::vector<Component *> looping_components_{}; |   std::vector<Component *> looping_components_{}; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user