7#ifdef ESPHOME_THREAD_MULTI_ATOMICS
26 friend void ::esphome::retry_handler(
const std::shared_ptr<RetryArgs> &args);
31 template<
typename... Ts>
friend class DelayAction;
36 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
37 void set_timeout(Component *
component, const std::
string &name,
uint32_t timeout, std::function<
void()> &&func);
47 void set_timeout(Component *
component, const
char *name,
uint32_t timeout, std::function<
void()> &&func);
51 void set_timeout(Component *
component, InternalSchedulerID
id,
uint32_t timeout, std::function<
void()> &&func) {
52 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID_INTERNAL,
nullptr,
53 static_cast<uint32_t>(
id), timeout, std::move(func));
56 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
57 bool cancel_timeout(Component *
component, const std::
string &name);
58 bool cancel_timeout(Component *
component, const
char *name);
60 bool cancel_timeout(Component *
component, InternalSchedulerID
id) {
61 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
62 SchedulerItem::TIMEOUT);
65 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
66 void set_interval(Component *
component, const std::
string &name,
uint32_t interval, std::function<
void()> &&func);
76 void set_interval(Component *
component, const
char *name,
uint32_t interval, std::function<
void()> &&func);
80 void set_interval(Component *
component, InternalSchedulerID
id,
uint32_t interval, std::function<
void()> &&func) {
81 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID_INTERNAL,
nullptr,
82 static_cast<uint32_t>(
id), interval, std::move(func));
85 ESPDEPRECATED(
"Use const char* or uint32_t overload instead. Removed in 2026.7.0",
"2026.1.0")
86 bool cancel_interval(Component *
component, const std::
string &name);
87 bool cancel_interval(Component *
component, const
char *name);
89 bool cancel_interval(Component *
component, InternalSchedulerID
id) {
90 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
91 SchedulerItem::INTERVAL);
95 ESPDEPRECATED(
"set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
97 void set_retry(Component *
component, const std::
string &name,
uint32_t initial_wait_time, uint8_t max_attempts,
98 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
100 ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
102 void set_retry(Component *
component, const
char *name,
uint32_t initial_wait_time, uint8_t max_attempts,
103 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
105 ESPDEPRECATED("set_retry is deprecated and will be removed in 2026.8.0. Use set_timeout or set_interval instead.",
108 std::function<RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
111 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
112 bool cancel_retry(Component *
component, const std::
string &name);
114 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
115 bool cancel_retry(Component *
component, const
char *name);
117 ESPDEPRECATED("cancel_retry is deprecated and will be removed in 2026.8.0.", "2026.2.0")
128 optional<uint32_t> next_schedule_in(
uint32_t now);
134 void process_to_add();
138 enum class NameType : uint8_t {
142 NUMERIC_ID_INTERNAL = 3
146 struct SchedulerItem {
151 const char *static_name;
163 std::function<void()> callback;
164 uint16_t next_execution_high_;
166#ifdef ESPHOME_THREAD_MULTI_ATOMICS
171 std::atomic<uint8_t> remove{0};
175 NameType name_type_ : 2;
183 NameType name_type_ : 2;
192 next_execution_low_(0),
193 next_execution_high_(0),
194#ifdef ESPHOME_THREAD_MULTI_ATOMICS
197 name_type_(NameType::STATIC_STRING),
202 name_type_(NameType::STATIC_STRING),
205 name_.static_name =
nullptr;
209 ~SchedulerItem() =
default;
212 SchedulerItem(
const SchedulerItem &) =
delete;
213 SchedulerItem &operator=(
const SchedulerItem &) =
delete;
216 SchedulerItem(SchedulerItem &&) =
delete;
217 SchedulerItem &operator=(SchedulerItem &&) =
delete;
220 const char *get_name()
const {
return (name_type_ == NameType::STATIC_STRING) ? name_.static_name :
nullptr; }
223 uint32_t get_name_hash_or_id()
const {
return (name_type_ != NameType::STATIC_STRING) ? name_.hash_or_id : 0; }
226 NameType get_name_type()
const {
return name_type_; }
230 void set_name(NameType
type,
const char *static_name,
uint32_t hash_or_id) {
231 if (
type == NameType::STATIC_STRING) {
232 name_.static_name = static_name;
234 name_.hash_or_id = hash_or_id;
239 static bool cmp(SchedulerItem *a, SchedulerItem *b);
244 constexpr uint64_t get_next_execution()
const {
245 return (
static_cast<uint64_t
>(next_execution_high_) << 32) | next_execution_low_;
248 constexpr void set_next_execution(uint64_t value) {
249 next_execution_low_ =
static_cast<uint32_t>(value);
252 next_execution_high_ =
static_cast<uint16_t
>(value >> 32);
254 constexpr const char *get_type_str()
const {
return (
type == TIMEOUT) ?
"timeout" :
"interval"; }
255 const LogString *get_source()
const {
return component ?
component->get_component_log_str() : LOG_STR(
"unknown"); }
260 void set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
const char *static_name,
261 uint32_t hash_or_id,
uint32_t delay, std::function<
void()> &&func,
bool is_retry =
false,
262 bool skip_cancel =
false);
266#pragma GCC diagnostic push
267#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
268 void set_retry_common_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
269 uint32_t initial_wait_time, uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
270 float backoff_increase_factor);
271#pragma GCC diagnostic pop
273 bool cancel_retry_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id);
278 uint64_t millis_64_from_(
uint32_t now) {
279#ifdef USE_NATIVE_64BIT_TIME
283 return Millis64Impl::compute(now);
293 SchedulerItem *pop_raw_locked_();
296 SchedulerItem *get_item_from_pool_locked_();
301 bool cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
302 SchedulerItem::Type
type,
bool match_retry =
false);
305 bool cancel_item_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
306 SchedulerItem::Type
type,
bool match_retry =
false);
309 inline bool HOT names_match_static_(
const char *name1,
const char *name2)
const {
314 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
320 inline bool HOT matches_item_locked_(SchedulerItem *item, Component *
component, NameType name_type,
321 const char *static_name,
uint32_t hash_or_id, SchedulerItem::Type
type,
322 bool match_retry,
bool skip_removed =
true)
const {
328 if (item->component !=
component || item->type !=
type || (skip_removed && this->is_item_removed_locked_(item)) ||
329 (match_retry && !item->is_retry)) {
333 if (item->get_name_type() != name_type)
336 if (name_type == NameType::STATIC_STRING) {
337 return this->names_match_static_(item->get_name(), static_name);
339 return item->get_name_hash_or_id() == hash_or_id;
346 bool should_skip_item_(SchedulerItem *item)
const {
347 return is_item_removed_(item) || (item->component !=
nullptr && item->component->is_failed());
356 void recycle_item_main_loop_(SchedulerItem *item);
359 void full_cleanup_removed_items_();
370 is_retry_cancelled_locked_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id);
372#ifdef ESPHOME_DEBUG_SCHEDULER
374 void debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
375 SchedulerItem::Type
type,
uint32_t delay, uint64_t now);
378#ifndef ESPHOME_THREAD_SINGLE
380 inline void process_defer_queue_(
uint32_t &now) {
400 if (this->defer_empty_())
410 this->defer_count_clear_();
411 size_t defer_queue_end = this->defer_queue_.size();
412 if (this->defer_queue_front_ >= defer_queue_end) {
413 this->lock_.unlock();
416 while (this->defer_queue_front_ < defer_queue_end) {
422 item = this->defer_queue_[this->defer_queue_front_];
423 this->defer_queue_[this->defer_queue_front_] =
nullptr;
424 this->defer_queue_front_++;
425 this->lock_.unlock();
429 if (!this->should_skip_item_(item)) {
430 now = this->execute_item_(item, now);
434 this->recycle_item_main_loop_(item);
437 this->cleanup_defer_queue_locked_();
438 this->lock_.unlock();
445 inline void cleanup_defer_queue_locked_() {
447 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
449 this->defer_queue_.clear();
453 this->compact_defer_queue_locked_();
455 this->defer_queue_front_ = 0;
461 void __attribute__((noinline)) compact_defer_queue_locked_();
468 bool is_item_removed_(SchedulerItem *item)
const {
469#ifdef ESPHOME_THREAD_MULTI_ATOMICS
471 return item->remove.load(std::memory_order_acquire);
483 bool is_item_removed_locked_(SchedulerItem *item)
const {
484#ifdef ESPHOME_THREAD_MULTI_ATOMICS
486 return item->remove.load(std::memory_order_relaxed);
496 void set_item_removed_(SchedulerItem *item,
bool removed) {
497#ifdef ESPHOME_THREAD_MULTI_ATOMICS
501 item->remove.store(removed ? 1 : 0, removed ? std::memory_order_release : std::memory_order_relaxed);
506 item->remove = removed;
514 __attribute__((noinline))
size_t mark_matching_items_removed_locked_(std::vector<SchedulerItem *> &container,
515 Component *
component, NameType name_type,
516 const char *static_name,
uint32_t hash_or_id,
517 SchedulerItem::Type
type,
bool match_retry) {
519 for (
auto *item : container) {
520 if (this->matches_item_locked_(item,
component, name_type, static_name, hash_or_id,
type, match_retry)) {
521 this->set_item_removed_(item,
true);
529 std::vector<SchedulerItem *> items_;
530 std::vector<SchedulerItem *> to_add_;
532#ifndef ESPHOME_THREAD_SINGLE
538#ifdef ESPHOME_THREAD_MULTI_ATOMICS
539 std::atomic<uint32_t> to_add_count_{0};
550 bool to_add_empty_()
const {
551#ifdef ESPHOME_THREAD_SINGLE
552 return this->to_add_.empty();
553#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
554 return this->to_add_count_.load(std::memory_order_relaxed) == 0;
561 void to_add_count_increment_() {
562#ifdef ESPHOME_THREAD_SINGLE
564#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
565 this->to_add_count_.fetch_add(1, std::memory_order_relaxed);
567 this->to_add_count_++;
572 void to_add_count_clear_() {
573#ifdef ESPHOME_THREAD_SINGLE
575#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
576 this->to_add_count_.store(0, std::memory_order_relaxed);
578 this->to_add_count_ = 0;
582#ifndef ESPHOME_THREAD_SINGLE
586 std::vector<SchedulerItem *> defer_queue_;
587 size_t defer_queue_front_{0};
590#ifdef ESPHOME_THREAD_MULTI_ATOMICS
591 std::atomic<uint32_t> defer_count_{0};
596 bool defer_empty_()
const {
599#ifdef ESPHOME_THREAD_MULTI_ATOMICS
600 return this->defer_count_.load(std::memory_order_relaxed) == 0;
606 void defer_count_increment_() {
607#ifdef ESPHOME_THREAD_MULTI_ATOMICS
608 this->defer_count_.fetch_add(1, std::memory_order_relaxed);
610 this->defer_count_++;
614 void defer_count_clear_() {
615#ifdef ESPHOME_THREAD_MULTI_ATOMICS
616 this->defer_count_.store(0, std::memory_order_relaxed);
618 this->defer_count_ = 0;
627#ifdef ESPHOME_THREAD_MULTI_ATOMICS
628 std::atomic<uint32_t> to_remove_{0};
634 bool to_remove_empty_()
const {
635#ifdef ESPHOME_THREAD_MULTI_ATOMICS
636 return this->to_remove_.load(std::memory_order_relaxed) == 0;
637#elif defined(ESPHOME_THREAD_SINGLE)
638 return this->to_remove_ == 0;
644 void to_remove_add_(
uint32_t count) {
645#ifdef ESPHOME_THREAD_MULTI_ATOMICS
646 this->to_remove_.fetch_add(count, std::memory_order_relaxed);
648 this->to_remove_ += count;
652 void to_remove_decrement_() {
653#ifdef ESPHOME_THREAD_MULTI_ATOMICS
654 this->to_remove_.fetch_sub(1, std::memory_order_relaxed);
660 void to_remove_clear_() {
661#ifdef ESPHOME_THREAD_MULTI_ATOMICS
662 this->to_remove_.store(0, std::memory_order_relaxed);
664 this->to_remove_ = 0;
669#ifdef ESPHOME_THREAD_MULTI_ATOMICS
670 return this->to_remove_.load(std::memory_order_relaxed);
672 return this->to_remove_;
684 std::vector<SchedulerItem *> scheduler_item_pool_;
686#ifdef ESPHOME_DEBUG_SCHEDULER
690 size_t debug_live_items_{0};
694 bool debug_verify_no_leak_()
const;
struct @65::@66 __attribute__
const Component * component
Providing packet encoding functions for exchanging data with a remote host.
void retry_handler(const std::shared_ptr< RetryArgs > &args)
const char int const __FlashStringHelper va_list args
struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq