mirror of
https://github.com/esphome/esphome.git
synced 2026-08-31 18:16:03 +00:00
[core] coerce set_interval(0) to 1ms to prevent scheduler spin
Users (notably PollingComponents with update_interval: 0ms) have historically relied on set_interval(0) as a pseudo-loop() mechanism. A literal interval=0 causes Scheduler::call() to spin — the item is always 'due now' after re-scheduling, so the scheduler loop never returns, starves the main loop, and triggers a WDT reset in the field. Coerce interval=0 to 1ms at creation so existing code keeps working at ~1kHz instead of spinning, while still emitting the warning pointing authors at HighFrequencyLoopRequester (the intended mechanism for running fast in the main loop). Zero-delay timeouts (defer/set_timeout) remain legitimate one-shots and are unaffected — defer is a one-shot, not a spin risk.
This commit is contained in:
@@ -144,13 +144,17 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
||||
return;
|
||||
}
|
||||
|
||||
// An interval of 0 means "fire every tick forever," which is misuse: it
|
||||
// asks the main loop to spin unbounded. The correct mechanism for running
|
||||
// fast in the main loop is HighFrequencyLoopRequester, not a zero-delay
|
||||
// interval. Zero-delay timeouts (defer) remain legitimate one-shots.
|
||||
// An interval of 0 means "fire every tick forever," which is misuse: the
|
||||
// item would always be due, causing Scheduler::call() to spin and starve
|
||||
// the main loop (WDT reset in the field). Coerce to 1ms so existing code
|
||||
// using update_interval=0ms as a pseudo-loop() continues to work at ~1kHz,
|
||||
// and warn so authors can migrate to HighFrequencyLoopRequester which is
|
||||
// the intended mechanism for running fast in the main loop. Zero-delay
|
||||
// timeouts (defer) remain legitimate one-shots and are not affected.
|
||||
if (type == SchedulerItem::INTERVAL && delay == 0) [[unlikely]] {
|
||||
ESP_LOGW(TAG, "[%s] set_interval(0) is misuse — use HighFrequencyLoopRequester",
|
||||
ESP_LOGW(TAG, "[%s] set_interval(0) is misuse — coercing to 1ms. Use HighFrequencyLoopRequester instead.",
|
||||
component ? LOG_STR_ARG(component->get_component_log_str()) : LOG_STR_LITERAL("?"));
|
||||
delay = 1;
|
||||
}
|
||||
|
||||
// Take lock early to protect scheduler_item_pool_ access and retry-cancelled check
|
||||
|
||||
Reference in New Issue
Block a user