mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
Revert "[core] Switch Scheduler::call now_64 plumbing from struct to out-param"
This reverts commit 4d7033df4f.
This commit is contained in:
@@ -83,8 +83,7 @@ void Application::setup() {
|
||||
// Service scheduler and process pending loop enables to handle GPIO
|
||||
// interrupts during setup. During setup we always run the component
|
||||
// phase (no loop_interval_ gate), so call both helpers unconditionally.
|
||||
uint64_t setup_sched_now_64_unused;
|
||||
this->scheduler_tick_(MillisInternal::get(), setup_sched_now_64_unused);
|
||||
this->scheduler_tick_(MillisInternal::get());
|
||||
{
|
||||
ComponentPhaseGuard phase_guard{*this};
|
||||
|
||||
|
||||
+12
-14
@@ -410,7 +410,7 @@ class Application {
|
||||
void enable_component_loop_(Component *component);
|
||||
void enable_pending_loops_();
|
||||
void activate_looping_component_(uint16_t index);
|
||||
inline uint32_t ESPHOME_ALWAYS_INLINE scheduler_tick_(uint32_t now, uint64_t &now_64_out);
|
||||
inline Scheduler::CallResult ESPHOME_ALWAYS_INLINE scheduler_tick_(uint32_t now);
|
||||
|
||||
// RAII guard for a component loop phase. Constructor processes any pending
|
||||
// enable_loop requests from ISRs and marks in_loop_ so reentrant
|
||||
@@ -535,12 +535,12 @@ extern Application App; // NOLINT(cppcoreguidelines-avoid-non-const-global-vari
|
||||
// 64-bit `now_64` (or 0 if any item fired — then stale). The main loop forwards
|
||||
// now_64 to next_schedule_in() to avoid a second esp_timer_get_time() MMIO read
|
||||
// per iteration; 0 means "compute fresh".
|
||||
inline uint32_t ESPHOME_ALWAYS_INLINE Application::scheduler_tick_(uint32_t now, uint64_t &now_64_out) {
|
||||
inline Scheduler::CallResult ESPHOME_ALWAYS_INLINE Application::scheduler_tick_(uint32_t now) {
|
||||
#ifdef USE_HOST
|
||||
// Drain wake notifications first to clear socket for next wake.
|
||||
wake_drain_notifications();
|
||||
#endif
|
||||
return this->scheduler.call(now, now_64_out);
|
||||
return this->scheduler.call(now);
|
||||
}
|
||||
|
||||
// Phase B entry: only invoked when a component loop phase is about to run.
|
||||
@@ -580,14 +580,12 @@ inline void ESPHOME_ALWAYS_INLINE Application::loop() {
|
||||
// Phase A: always service the scheduler. Decouples scheduler cadence from
|
||||
// loop_interval_ so raised intervals (for power savings) don't drag scheduled
|
||||
// items forward. A tick that only runs the scheduler is cheap.
|
||||
// scheduler_tick_ returns the advanced `now` (for wdt monotonicity) and fills
|
||||
// sched_now_64 with the 64-bit timestamp Scheduler::call() already computed —
|
||||
// forward that to the next_schedule_in() call below so we don't re-read
|
||||
// esp_timer_get_time() a second time per iteration. 0 means "stale, recompute".
|
||||
// Out-param keeps the return path in a single register and avoids a 16-byte
|
||||
// struct-copy on the caller's stack.
|
||||
uint64_t sched_now_64_raw;
|
||||
uint32_t now = this->scheduler_tick_(MillisInternal::get(), sched_now_64_raw);
|
||||
// scheduler_tick_ returns the advanced `now` (for wdt monotonicity) plus the
|
||||
// 64-bit `now_64` Scheduler::call() already computed — forward that to the
|
||||
// next_schedule_in() call below so we don't re-read esp_timer_get_time() a
|
||||
// second time per iteration. 0 means "stale, recompute".
|
||||
const Scheduler::CallResult sched_result = this->scheduler_tick_(MillisInternal::get());
|
||||
uint32_t now = sched_result.now;
|
||||
#ifdef USE_RUNTIME_STATS
|
||||
// Capture immediately after scheduler_tick_ returns so the post-scheduler
|
||||
// feed_wdt_with_time slice can be separated from the scheduler slice in
|
||||
@@ -707,10 +705,10 @@ inline void ESPHOME_ALWAYS_INLINE Application::loop() {
|
||||
const uint32_t elapsed_since_phase = now - this->last_loop_;
|
||||
const uint32_t until_phase =
|
||||
(elapsed_since_phase >= this->loop_interval_) ? 0 : (this->loop_interval_ - elapsed_since_phase);
|
||||
// Resolve the sched_now_64_raw sentinel here so next_schedule_in() can assume a valid
|
||||
// Resolve the sched_result.now_64 sentinel here so next_schedule_in() can assume a valid
|
||||
// non-zero input and keep the cold clock-read path out of its body. When call() fired items
|
||||
// sched_now_64_raw is 0 (stale) and we read the clock fresh; otherwise we reuse it.
|
||||
const uint64_t sched_now_64 = sched_now_64_raw != 0 ? sched_now_64_raw : this->scheduler.millis_64_from(now);
|
||||
// sched_result.now_64 is 0 (stale) and we read the clock fresh; otherwise we reuse it.
|
||||
const uint64_t sched_now_64 = sched_result.now_64 != 0 ? sched_result.now_64 : this->scheduler.millis_64_from(now);
|
||||
const uint32_t until_sched = this->scheduler.next_schedule_in(sched_now_64).value_or(until_phase);
|
||||
delay_time = std::min(until_phase, until_sched);
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ void HOT Scheduler::process_defer_queue_slow_path_(uint32_t &now) {
|
||||
}
|
||||
#endif /* not ESPHOME_THREAD_SINGLE */
|
||||
|
||||
uint32_t HOT Scheduler::call(uint32_t now, uint64_t &now_64_out) {
|
||||
Scheduler::CallResult HOT Scheduler::call(uint32_t now) {
|
||||
#ifndef ESPHOME_THREAD_SINGLE
|
||||
this->process_defer_queue_(now);
|
||||
#endif /* not ESPHOME_THREAD_SINGLE */
|
||||
@@ -752,11 +752,10 @@ uint32_t HOT Scheduler::call(uint32_t now, uint64_t &now_64_out) {
|
||||
#endif
|
||||
// execute_item_() advances `now` as items fire; return it so the caller
|
||||
// stays monotonic with last_wdt_feed_.
|
||||
// The now_64 we pass back is only usable if NO items fired — execute_item_
|
||||
// only advances the uint32 `now`, leaving our local now_64 stale. Signal
|
||||
// stale with the 0 sentinel so next_schedule_in() reads the clock fresh.
|
||||
now_64_out = executed_any_item ? 0 : now_64;
|
||||
return now;
|
||||
// The returned now_64 is only usable if NO items fired — execute_item_ only
|
||||
// advances the uint32 `now`, leaving our local now_64 stale. Signal stale
|
||||
// with the 0 sentinel so next_schedule_in() reads the clock fresh.
|
||||
return CallResult{now, executed_any_item ? 0 : now_64};
|
||||
}
|
||||
void HOT Scheduler::process_to_add_slow_path_() {
|
||||
LockGuard guard{this->lock_};
|
||||
|
||||
+16
-10
@@ -136,17 +136,23 @@ class Scheduler {
|
||||
// IMPORTANT: This method should only be called from the main thread (loop task).
|
||||
optional<uint32_t> next_schedule_in(uint64_t now_64);
|
||||
|
||||
// Execute all scheduled items that are ready.
|
||||
// Result of Scheduler::call().
|
||||
// now – advanced uint32 millis timestamp (monotonic with the caller's wdt feed).
|
||||
// now_64 – 64-bit millis value Scheduler used for item dispatch, OR 0 if any item
|
||||
// fired (in that case now_64 is stale because execute_item_ only advances
|
||||
// the uint32 `now`). A subsequent next_schedule_in() treats 0 as "compute
|
||||
// fresh" and non-zero as "reuse this value", saving a second millis_64()
|
||||
// / esp_timer_get_time() call per main-loop iteration.
|
||||
struct CallResult {
|
||||
uint32_t now;
|
||||
uint64_t now_64;
|
||||
};
|
||||
|
||||
// Execute all scheduled items that are ready
|
||||
// @param now Fresh timestamp from millis() - must not be stale/cached
|
||||
// @param now_64_out Out-param set to the 64-bit `now` that Scheduler used for item
|
||||
// dispatch, OR 0 if any item fired (in that case the value is stale because
|
||||
// execute_item_ only advances the uint32 `now`). A subsequent next_schedule_in()
|
||||
// treats 0 as "compute fresh" and non-zero as "reuse this value", saving a
|
||||
// second millis_64() / esp_timer_get_time() call per main-loop iteration.
|
||||
// Out-param (rather than struct return) keeps the return path in a single
|
||||
// register and avoids a 16-byte struct-copy on the loop caller's stack.
|
||||
// @return Advanced `now` (monotonic with the caller's wdt feed).
|
||||
uint32_t call(uint32_t now, uint64_t &now_64_out);
|
||||
// @return Both advanced `now` (for wdt monotonicity) and `now_64` (for pipe-through
|
||||
// to next_schedule_in()). See CallResult.
|
||||
CallResult call(uint32_t now);
|
||||
|
||||
// Move items from to_add_ into the main heap.
|
||||
// IMPORTANT: This method should only be called from the main thread (loop task).
|
||||
|
||||
Reference in New Issue
Block a user