15static const char *
const TAG =
"scheduler";
19static constexpr uint32_t MAX_LOGICALLY_DELETED_ITEMS = 5;
21static constexpr uint32_t MAX_INTERVAL_DELAY = 5000;
23#if defined(ESPHOME_LOG_HAS_VERBOSE) || defined(ESPHOME_DEBUG_SCHEDULER)
27struct SchedulerNameLog {
34 const char *
format(Scheduler::NameType name_type,
const char *static_name,
uint32_t hash_or_id) {
35 using NameType = Scheduler::NameType;
36 if (name_type == NameType::STATIC_STRING) {
40 ESPHOME_strncpy_P(buffer, ESPHOME_PSTR(
"(null)"),
sizeof(buffer));
42 }
else if (name_type == NameType::HASHED_STRING) {
43 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"hash:0x%08" PRIX32), hash_or_id);
45 }
else if (name_type == NameType::NUMERIC_ID) {
46 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"id:%" PRIu32), hash_or_id);
48 }
else if (name_type == NameType::NUMERIC_ID_INTERNAL) {
49 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"iid:%" PRIu32), hash_or_id);
54 ESPHOME_snprintf_P(buffer,
sizeof(buffer), ESPHOME_PSTR(
"self:%p"),
55 const_cast<void *
>(
static_cast<const void *
>(static_name)));
65#ifdef ESPHOME_DEBUG_SCHEDULER
67static void validate_static_string(
const char *name) {
73 uintptr_t addr =
reinterpret_cast<uintptr_t
>(
name);
77 uintptr_t stack_addr =
reinterpret_cast<uintptr_t
>(&stack_var);
81 if (addr > (stack_addr - 0x2000) && addr < (stack_addr + 0x2000)) {
83 "WARNING: Scheduler name '%s' at %p appears to be on the stack - this is unsafe!\n"
84 " Stack reference at %p",
85 name, name, &stack_var);
90 static const char *static_str =
"test";
91 uintptr_t static_addr =
reinterpret_cast<uintptr_t
>(static_str);
94 if (addr > static_addr + 0x100000 || (static_addr > 0x100000 && addr < static_addr - 0x100000)) {
95 ESP_LOGW(TAG,
"WARNING: Scheduler name '%s' at %p might be on heap (static ref at %p)", name, name, static_str);
108 uint32_t max_offset = std::min(
delay / 2, MAX_INTERVAL_DELAY);
116bool Scheduler::is_retry_cancelled_locked_(Component *
component, NameType name_type,
const char *static_name,
118 for (
auto *container : {&this->items_, &this->to_add_}) {
119 for (
auto *item : *container) {
120 if (item !=
nullptr && this->is_item_removed_locked_(item) &&
121 this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id, SchedulerItem::TIMEOUT,
132void HOT Scheduler::set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
134 std::function<
void()> &&func,
bool is_retry,
bool skip_cancel,
135 const LogString *source) {
139 LockGuard guard{this->lock_};
140 this->cancel_item_locked_(
component, name_type, static_name, hash_or_id,
type,
false,
153 if (
type == SchedulerItem::INTERVAL &&
delay == 0) [[unlikely]] {
154 ESP_LOGE(TAG,
"[%s] set_interval(0) would spin main loop - coercing to 1ms (use HighFrequencyLoopRequester)",
160 LockGuard guard{this->lock_};
165 if (is_retry &&
delay != 0 && (name_type != NameType::STATIC_STRING || static_name !=
nullptr) &&
166 type == SchedulerItem::TIMEOUT &&
167 this->is_retry_cancelled_locked_(
component, name_type, static_name, hash_or_id)) {
168#ifdef ESPHOME_DEBUG_SCHEDULER
169 SchedulerNameLog skip_name_log;
170 ESP_LOGD(TAG,
"Skipping retry '%s' - found cancelled item",
171 skip_name_log.format(name_type, static_name, hash_or_id));
177 SchedulerItem *item = this->get_item_from_pool_locked_();
179 if (name_type == NameType::SELF_POINTER) {
180 item->source_name = source;
184 item->set_name(name_type, static_name, hash_or_id);
191 item->callback.~function();
192 new (&item->callback) std::function<
void()>(std::move(func));
194 this->set_item_removed_(item,
false);
195 item->is_retry = is_retry;
199 auto *target = &this->to_add_;
201#ifndef ESPHOME_THREAD_SINGLE
204 if (
delay == 0 &&
type == SchedulerItem::TIMEOUT) {
206 target = &this->defer_queue_;
214 if (
type == SchedulerItem::INTERVAL) {
215 item->interval =
delay;
218 item->set_next_execution(now_64 + offset);
219#ifdef ESPHOME_LOG_HAS_VERBOSE
220 SchedulerNameLog name_log;
221 ESP_LOGV(TAG,
"Scheduler interval for %s is %" PRIu32
"ms, offset %" PRIu32
"ms",
222 name_log.format(name_type, static_name, hash_or_id),
delay, offset);
226 item->set_next_execution(now_64 +
delay);
229#ifdef ESPHOME_DEBUG_SCHEDULER
230 this->debug_log_timer_(item, name_type, static_name, hash_or_id,
type,
delay, now_64);
236 if (!skip_cancel && (name_type != NameType::STATIC_STRING || static_name !=
nullptr)) {
237 this->cancel_item_locked_(
component, name_type, static_name, hash_or_id,
type,
false,
240 target->push_back(item);
241 if (target == &this->to_add_) {
242 this->to_add_count_increment_locked_();
244#ifndef ESPHOME_THREAD_SINGLE
246 this->defer_count_increment_locked_();
251void HOT Scheduler::set_timeout(Component *
component,
const char *name,
uint32_t timeout,
252 std::function<
void()> &&func) {
253 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::STATIC_STRING, name, 0, timeout,
258 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID,
nullptr,
id, timeout,
261bool HOT Scheduler::cancel_timeout(Component *
component,
const char *name) {
262 return this->cancel_item_(
component, NameType::STATIC_STRING, name, 0, SchedulerItem::TIMEOUT);
265 return this->cancel_item_(
component, NameType::NUMERIC_ID,
nullptr,
id, SchedulerItem::TIMEOUT);
267void HOT Scheduler::set_interval(Component *
component,
const char *name,
uint32_t interval,
268 std::function<
void()> &&func) {
269 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::STATIC_STRING, name, 0, interval,
273 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID,
nullptr,
id, interval,
276bool HOT Scheduler::cancel_interval(Component *
component,
const char *name) {
277 return this->cancel_item_(
component, NameType::STATIC_STRING, name, 0, SchedulerItem::INTERVAL);
280 return this->cancel_item_(
component, NameType::NUMERIC_ID,
nullptr,
id, SchedulerItem::INTERVAL);
287void HOT Scheduler::set_timeout(
const void *self,
uint32_t timeout, std::function<
void()> &&func) {
288 this->set_timer_common_(
nullptr, SchedulerItem::TIMEOUT, NameType::SELF_POINTER,
static_cast<const char *
>(self), 0,
289 timeout, std::move(func));
291void HOT Scheduler::set_interval(
const void *self,
uint32_t interval, std::function<
void()> &&func) {
292 this->set_timer_common_(
nullptr, SchedulerItem::INTERVAL, NameType::SELF_POINTER,
static_cast<const char *
>(self), 0,
293 interval, std::move(func));
295bool HOT Scheduler::cancel_timeout(
const void *self) {
296 return this->cancel_item_(
nullptr, NameType::SELF_POINTER,
static_cast<const char *
>(self), 0,
297 SchedulerItem::TIMEOUT);
299bool HOT Scheduler::cancel_interval(
const void *self) {
300 return this->cancel_item_(
nullptr, NameType::SELF_POINTER,
static_cast<const char *
>(self), 0,
301 SchedulerItem::INTERVAL);
306#pragma GCC diagnostic push
307#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
313 Scheduler *scheduler;
316 const char *static_name;
320 float backoff_increase_factor;
321 Scheduler::NameType name_type;
322 uint8_t retry_countdown;
332 const char *static_name = (
args->name_type == Scheduler::NameType::STATIC_STRING) ?
args->name_.static_name :
nullptr;
333 uint32_t hash_or_id = (
args->name_type != Scheduler::NameType::STATIC_STRING) ?
args->name_.hash_or_id : 0;
334 args->scheduler->set_timer_common_(
335 args->component, Scheduler::SchedulerItem::TIMEOUT,
args->name_type, static_name, hash_or_id,
336 args->current_interval, [
args]() { retry_handler(args); },
339 args->current_interval *=
args->backoff_increase_factor;
342void HOT Scheduler::set_retry_common_(Component *
component, NameType name_type,
const char *static_name,
344 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor) {
345 this->cancel_retry_(
component, name_type, static_name, hash_or_id);
350#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
352 SchedulerNameLog name_log;
353 ESP_LOGVV(TAG,
"set_retry(name='%s', initial_wait_time=%" PRIu32
", max_attempts=%u, backoff_factor=%0.1f)",
354 name_log.format(name_type, static_name, hash_or_id), initial_wait_time, max_attempts,
355 backoff_increase_factor);
359 if (backoff_increase_factor < 0.0001f) {
360 ESP_LOGE(TAG,
"set_retry: backoff_factor %0.1f too small, using 1.0: %s", backoff_increase_factor,
361 (name_type == NameType::STATIC_STRING && static_name) ? static_name :
"");
362 backoff_increase_factor = 1;
365 auto args = std::make_shared<RetryArgs>();
366 args->func = std::move(func);
368 args->scheduler =
this;
369 args->name_type = name_type;
370 if (name_type == NameType::STATIC_STRING) {
371 args->name_.static_name = static_name;
373 args->name_.hash_or_id = hash_or_id;
375 args->current_interval = initial_wait_time;
377 args->retry_countdown = max_attempts;
380 this->set_timer_common_(
385void HOT Scheduler::set_retry(Component *
component,
const char *name,
uint32_t initial_wait_time, uint8_t max_attempts,
386 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor) {
387 this->set_retry_common_(
component, NameType::STATIC_STRING, name, 0, initial_wait_time, max_attempts, std::move(func),
388 backoff_increase_factor);
391bool HOT Scheduler::cancel_retry_(Component *
component, NameType name_type,
const char *static_name,
393 return this->cancel_item_(
component, name_type, static_name, hash_or_id, SchedulerItem::TIMEOUT,
396bool HOT Scheduler::cancel_retry(Component *
component,
const char *name) {
397 return this->cancel_retry_(
component, NameType::STATIC_STRING, name, 0);
400void HOT Scheduler::set_retry(Component *
component,
const std::string &name,
uint32_t initial_wait_time,
401 uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
402 float backoff_increase_factor) {
403 this->set_retry_common_(
component, NameType::HASHED_STRING,
nullptr,
fnv1a_hash(name), initial_wait_time,
404 max_attempts, std::move(func), backoff_increase_factor);
407bool HOT Scheduler::cancel_retry(Component *
component,
const std::string &name) {
412 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor) {
413 this->set_retry_common_(
component, NameType::NUMERIC_ID,
nullptr,
id, initial_wait_time, max_attempts,
414 std::move(func), backoff_increase_factor);
418 return this->cancel_retry_(
component, NameType::NUMERIC_ID,
nullptr,
id);
421#pragma GCC diagnostic pop
423optional<uint32_t> HOT Scheduler::next_schedule_in(
uint32_t now) {
433#ifndef ESPHOME_THREAD_SINGLE
437 if (!this->defer_empty_())
443 if (!this->to_add_empty_())
448 if (!this->cleanup_())
451 SchedulerItem *item = this->items_[0];
452 const auto now_64 = this->millis_64_from_(now);
453 const uint64_t next_exec = item->get_next_execution();
454 if (next_exec < now_64)
456 return next_exec - now_64;
459void Scheduler::full_cleanup_removed_items_() {
465 LockGuard guard{this->lock_};
469 for (
size_t read = 0; read < this->items_.size(); ++read) {
470 if (!is_item_removed_locked_(this->items_[read])) {
472 this->items_[write] = this->items_[read];
476 this->recycle_item_main_loop_(this->items_[read]);
479 this->items_.erase(this->items_.begin() + write, this->items_.end());
481 std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
482 this->to_remove_clear_locked_();
485#ifndef ESPHOME_THREAD_SINGLE
486void Scheduler::compact_defer_queue_locked_() {
498 size_t remaining = this->defer_queue_.size() - this->defer_queue_front_;
499 for (
size_t i = 0; i < remaining; i++) {
500 this->defer_queue_[i] = this->defer_queue_[this->defer_queue_front_ + i];
504 this->defer_queue_.erase(this->defer_queue_.begin() + remaining, this->defer_queue_.end());
506void HOT Scheduler::process_defer_queue_slow_path_(
uint32_t &now) {
531 this->defer_count_clear_locked_();
532 size_t defer_queue_end = this->defer_queue_.size();
533 if (this->defer_queue_front_ >= defer_queue_end) {
534 this->lock_.unlock();
537 while (this->defer_queue_front_ < defer_queue_end) {
543 item = this->defer_queue_[this->defer_queue_front_];
544 this->defer_queue_[this->defer_queue_front_] =
nullptr;
545 this->defer_queue_front_++;
546 this->lock_.unlock();
550 if (!this->should_skip_item_(item)) {
551 now = this->execute_item_(item, now);
555 this->recycle_item_main_loop_(item);
558 this->cleanup_defer_queue_locked_();
559 this->lock_.unlock();
564#ifndef ESPHOME_THREAD_SINGLE
565 this->process_defer_queue_(now);
569 const auto now_64 = this->millis_64_from_(now);
570 this->process_to_add();
573 bool has_added_items =
false;
575#ifdef ESPHOME_DEBUG_SCHEDULER
576 static uint64_t last_print = 0;
578 if (now_64 - last_print > 2000) {
580 std::vector<SchedulerItem *> old_items;
581 ESP_LOGD(TAG,
"Items: count=%zu, pool=%zu, now=%" PRIu64, this->items_.size(), this->scheduler_item_pool_size_,
585 while (!this->items_.empty()) {
588 LockGuard guard{this->lock_};
589 item = this->pop_raw_locked_();
592 SchedulerNameLog name_log;
593 bool is_cancelled = is_item_removed_(item);
594 ESP_LOGD(TAG,
" %s '%s/%s' interval=%" PRIu32
" next_execution in %" PRIu64
"ms at %" PRIu64
"%s",
595 item->get_type_str(), LOG_STR_ARG(item->get_source()),
596 name_log.format(item->get_name_type(), item->get_name(), item->get_name_hash_or_id()), item->interval,
597 item->get_next_execution() - now_64, item->get_next_execution(), is_cancelled ?
" [CANCELLED]" :
"");
599 old_items.push_back(item);
604 LockGuard guard{this->lock_};
605 this->items_ = std::move(old_items);
607 std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
618 if (this->to_remove_count_() >= MAX_LOGICALLY_DELETED_ITEMS) {
619 this->full_cleanup_removed_items_();
627 while (!this->items_.empty()) {
629 SchedulerItem *item = this->items_[0];
630 if (item->get_next_execution() > now_64) {
635 if (this->is_item_failed_(item)) {
636 LockGuard guard{this->lock_};
637 this->recycle_item_main_loop_(this->pop_raw_locked_());
645#ifdef ESPHOME_THREAD_MULTI_NO_ATOMICS
648 LockGuard guard{this->lock_};
649 if (is_item_removed_locked_(item)) {
650 this->recycle_item_main_loop_(this->pop_raw_locked_());
651 this->to_remove_decrement_locked_();
657 if (is_item_removed_(item)) {
658 LockGuard guard{this->lock_};
659 this->recycle_item_main_loop_(this->pop_raw_locked_());
660 this->to_remove_decrement_locked_();
665#ifdef ESPHOME_DEBUG_SCHEDULER
667 SchedulerNameLog name_log;
668 ESP_LOGV(TAG,
"Running %s '%s/%s' with interval=%" PRIu32
" next_execution=%" PRIu64
" (now=%" PRIu64
")",
669 item->get_type_str(), LOG_STR_ARG(item->get_source()),
670 name_log.format(item->get_name_type(), item->get_name(), item->get_name_hash_or_id()), item->interval,
671 item->get_next_execution(), now_64);
678 now = this->execute_item_(item, now);
680 LockGuard guard{this->lock_};
684 SchedulerItem *executed_item = this->pop_raw_locked_();
686 if (this->is_item_removed_locked_(executed_item)) {
688 this->to_remove_decrement_locked_();
689 this->recycle_item_main_loop_(executed_item);
693 if (executed_item->type == SchedulerItem::INTERVAL) {
694 executed_item->set_next_execution(now_64 + executed_item->interval);
705 this->items_.push_back(executed_item);
706 std::push_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
709 this->recycle_item_main_loop_(executed_item);
712 has_added_items |= !this->to_add_.empty();
715 if (has_added_items) {
716 this->process_to_add();
719#ifdef ESPHOME_DEBUG_SCHEDULER
729 LockGuard guard{this->lock_};
730 this->debug_verify_no_leak_();
737void HOT Scheduler::process_to_add_slow_path_() {
738 LockGuard guard{this->lock_};
739 for (
auto *&it : this->to_add_) {
740 if (is_item_removed_locked_(it)) {
742 this->recycle_item_main_loop_(it);
747 this->items_.push_back(it);
748 std::push_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
750 this->to_add_.clear();
751 this->to_add_count_clear_locked_();
753bool HOT Scheduler::cleanup_slow_path_() {
762 LockGuard guard{this->lock_};
763 while (!this->items_.empty()) {
764 SchedulerItem *item = this->items_[0];
765 if (!this->is_item_removed_locked_(item))
767 this->to_remove_decrement_locked_();
768 this->recycle_item_main_loop_(this->pop_raw_locked_());
770 return !this->items_.empty();
772Scheduler::SchedulerItem *HOT Scheduler::pop_raw_locked_() {
773 std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
775 SchedulerItem *item = this->items_.back();
776 this->items_.pop_back();
787 const LogString *source;
788 if (item->get_name_type() == NameType::SELF_POINTER) {
790 source = item->source_name;
796 LoopBlockingGuard guard{
component, source, now};
808bool HOT Scheduler::cancel_item_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
809 SchedulerItem::Type
type,
bool match_retry) {
810 LockGuard guard{this->lock_};
813 return this->cancel_item_locked_(
component, name_type, static_name, hash_or_id,
type, match_retry);
822size_t Scheduler::mark_matching_items_removed_slow_locked_(std::vector<SchedulerItem *> &container,
823 Component *
component, NameType name_type,
824 const char *static_name,
uint32_t hash_or_id,
825 SchedulerItem::Type
type,
bool match_retry,
828 for (
auto *item : container) {
829 if (this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id,
type, match_retry)) {
830 this->set_item_removed_(item,
true);
839bool HOT Scheduler::cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name,
840 uint32_t hash_or_id, SchedulerItem::Type
type,
bool match_retry,
843 if (name_type == NameType::STATIC_STRING && static_name ==
nullptr) {
847 size_t total_cancelled = 0;
849#ifndef ESPHOME_THREAD_SINGLE
851 if (
type == SchedulerItem::TIMEOUT) {
852 total_cancelled += this->mark_matching_items_removed_locked_(this->defer_queue_,
component, name_type, static_name,
853 hash_or_id,
type, match_retry, find_first);
854 if (find_first && total_cancelled > 0)
865 size_t heap_cancelled = this->mark_matching_items_removed_locked_(this->items_,
component, name_type, static_name,
866 hash_or_id,
type, match_retry, find_first);
867 total_cancelled += heap_cancelled;
868 this->to_remove_add_locked_(heap_cancelled);
869 if (find_first && total_cancelled > 0)
874 total_cancelled += this->mark_matching_items_removed_locked_(this->to_add_,
component, name_type, static_name,
875 hash_or_id,
type, match_retry, find_first);
877 return total_cancelled > 0;
880bool HOT Scheduler::SchedulerItem::cmp(SchedulerItem *a, SchedulerItem *b) {
883 return (a->next_execution_high_ ==
b->next_execution_high_) ? (a->next_execution_low_ >
b->next_execution_low_)
884 : (a->next_execution_high_ >
b->next_execution_high_);
889void Scheduler::recycle_item_main_loop_(SchedulerItem *item) {
893 item->callback =
nullptr;
894 item->next_free = this->scheduler_item_pool_head_;
895 this->scheduler_item_pool_head_ = item;
896 this->scheduler_item_pool_size_++;
897#ifdef ESPHOME_DEBUG_SCHEDULER
898 ESP_LOGD(TAG,
"Recycled item to pool (pool size now: %zu)", this->scheduler_item_pool_size_);
910void __attribute__((noinline)) Scheduler::shrink_scheduler_vector_(std::vector<SchedulerItem *> *v) {
911 if (v->capacity() == v->size())
913 std::vector<SchedulerItem *> tmp;
914 tmp.reserve(v->size());
915 for (SchedulerItem *p : *v)
920void Scheduler::trim_freelist() {
921 LockGuard guard{this->lock_};
922 SchedulerItem *item = this->scheduler_item_pool_head_;
924 while (item !=
nullptr) {
925 SchedulerItem *next = item->next_free;
927#ifdef ESPHOME_DEBUG_SCHEDULER
928 this->debug_live_items_--;
933 this->scheduler_item_pool_head_ =
nullptr;
934 this->scheduler_item_pool_size_ = 0;
938 shrink_scheduler_vector_(&this->items_);
939 shrink_scheduler_vector_(&this->to_add_);
940#ifndef ESPHOME_THREAD_SINGLE
941 shrink_scheduler_vector_(&this->defer_queue_);
944#ifdef ESPHOME_DEBUG_SCHEDULER
945 ESP_LOGD(TAG,
"Freelist trimmed (%zu items freed)", freed);
951#ifdef ESPHOME_DEBUG_SCHEDULER
952void Scheduler::debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name,
955 if (name_type == NameType::STATIC_STRING && static_name !=
nullptr) {
956 validate_static_string(static_name);
960 SchedulerNameLog name_log;
961 const char *type_str = (
type == SchedulerItem::TIMEOUT) ?
"timeout" :
"interval";
962 if (
type == SchedulerItem::TIMEOUT) {
963 ESP_LOGD(TAG,
"set_%s(name='%s/%s', %s=%" PRIu32
")", type_str, LOG_STR_ARG(item->get_source()),
964 name_log.format(name_type, static_name, hash_or_id), type_str,
delay);
966 ESP_LOGD(TAG,
"set_%s(name='%s/%s', %s=%" PRIu32
", offset=%" PRIu32
")", type_str, LOG_STR_ARG(item->get_source()),
967 name_log.format(name_type, static_name, hash_or_id), type_str,
delay,
968 static_cast<uint32_t>(item->get_next_execution() - now));
975Scheduler::SchedulerItem *Scheduler::get_item_from_pool_locked_() {
976 if (this->scheduler_item_pool_head_ !=
nullptr) {
977 SchedulerItem *item = this->scheduler_item_pool_head_;
978 this->scheduler_item_pool_head_ = item->next_free;
979 this->scheduler_item_pool_size_--;
980#ifdef ESPHOME_DEBUG_SCHEDULER
981 ESP_LOGD(TAG,
"Reused item from pool (pool size now: %zu)", this->scheduler_item_pool_size_);
985#ifdef ESPHOME_DEBUG_SCHEDULER
986 ESP_LOGD(TAG,
"Allocated new item (pool empty)");
988 auto *item =
new SchedulerItem();
989#ifdef ESPHOME_DEBUG_SCHEDULER
990 this->debug_live_items_++;
995#ifdef ESPHOME_DEBUG_SCHEDULER
996bool Scheduler::debug_verify_no_leak_()
const {
999 size_t accounted = this->items_.size() + this->to_add_.size() + this->scheduler_item_pool_size_;
1000#ifndef ESPHOME_THREAD_SINGLE
1001 accounted += this->defer_queue_.size();
1003 if (accounted != this->debug_live_items_) {
1005 "SCHEDULER LEAK DETECTED: live=%" PRIu32
" but accounted=%" PRIu32
" (items=%" PRIu32
" to_add=%" PRIu32
1007#ifndef ESPHOME_THREAD_SINGLE
1011 static_cast<uint32_t>(this->debug_live_items_),
static_cast<uint32_t>(accounted),
1012 static_cast<uint32_t>(this->items_.size()),
static_cast<uint32_t>(this->to_add_.size()),
1013 static_cast<uint32_t>(this->scheduler_item_pool_size_)
1014#ifndef ESPHOME_THREAD_SINGLE
1016 static_cast<uint32_t>(this->defer_queue_.size())
void ESPHOME_ALWAYS_INLINE feed_wdt_with_time(uint32_t time)
Feed the task watchdog, hot entry.
const LogString * get_component_log_str() const ESPHOME_ALWAYS_INLINE
Get the integration where this component was declared as a LogString for logging.
ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.", "2026.2.0") void set_retry(const std uint32_t uint8_t std::function< RetryResult(uint8_t)> float backoff_increase_factor
struct @65::@66 __attribute__
Wake the main loop task from an ISR. ISR-safe.
const Component * component
const char int const __FlashStringHelper * format
void retry_handler(const std::shared_ptr< RetryArgs > &args)
const char int const __FlashStringHelper va_list args
uint32_t random_uint32()
Return a random 32-bit unsigned integer.
void HOT delay(uint32_t ms)
Application App
Global storage of Application pointer - only one Application can exist.
constexpr uint32_t fnv1a_hash(const char *str)
Calculate a FNV-1a hash of str.
constexpr uint32_t SCHEDULER_DONT_RUN