7#ifdef ESPHOME_THREAD_MULTI_ATOMICS
25 template<
typename... Ts>
friend class DelayAction;
36 void set_timeout(Component *
component,
const char *name,
uint32_t timeout, std::function<
void()> &&func);
40 void set_timeout(Component *
component, InternalSchedulerID
id,
uint32_t timeout, std::function<
void()> &&func) {
41 this->set_timer_common_(
component, SchedulerItem::TIMEOUT, NameType::NUMERIC_ID_INTERNAL,
nullptr,
42 static_cast<uint32_t>(
id), timeout, std::move(func));
45 bool cancel_timeout(Component *
component,
const char *name);
47 bool cancel_timeout(Component *
component, InternalSchedulerID
id) {
48 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
49 SchedulerItem::TIMEOUT);
60 void set_interval(Component *
component,
const char *name,
uint32_t interval, std::function<
void()> &&func);
64 void set_interval(Component *
component, InternalSchedulerID
id,
uint32_t interval, std::function<
void()> &&func) {
65 this->set_timer_common_(
component, SchedulerItem::INTERVAL, NameType::NUMERIC_ID_INTERNAL,
nullptr,
66 static_cast<uint32_t>(
id), interval, std::move(func));
69 bool cancel_interval(Component *
component,
const char *name);
71 bool cancel_interval(Component *
component, InternalSchedulerID
id) {
72 return this->cancel_item_(
component, NameType::NUMERIC_ID_INTERNAL,
nullptr,
static_cast<uint32_t>(
id),
73 SchedulerItem::INTERVAL);
84 optional<uint32_t> next_schedule_in(
uint32_t now);
104 inline void ESPHOME_ALWAYS_INLINE HOT process_to_add() {
105 if (this->to_add_empty_())
107 this->process_to_add_slow_path_();
113 enum class NameType : uint8_t {
117 NUMERIC_ID_INTERNAL = 3,
134 void set_timeout(
const void *self,
uint32_t timeout, std::function<
void()> &&func);
136 void set_interval(
const void *self,
uint32_t interval, std::function<
void()> &&func);
137 bool cancel_timeout(
const void *self);
138 bool cancel_interval(
const void *self);
141 struct SchedulerItem {
147 SchedulerItem *next_free;
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_ : 3;
182 NameType name_type_ : 3;
190 next_execution_low_(0),
191 next_execution_high_(0),
192#ifdef ESPHOME_THREAD_MULTI_ATOMICS
195 name_type_(NameType::STATIC_STRING) {
199 name_type_(NameType::STATIC_STRING) {
201 name_.static_name =
nullptr;
205 ~SchedulerItem() =
default;
208 SchedulerItem(
const SchedulerItem &) =
delete;
209 SchedulerItem &operator=(
const SchedulerItem &) =
delete;
212 SchedulerItem(SchedulerItem &&) =
delete;
213 SchedulerItem &operator=(SchedulerItem &&) =
delete;
217 const char *get_name()
const {
218 return (name_type_ == NameType::STATIC_STRING || name_type_ == NameType::SELF_POINTER) ? name_.static_name
223 uint32_t get_name_hash_or_id()
const {
224 return (name_type_ != NameType::STATIC_STRING && name_type_ != NameType::SELF_POINTER) ? name_.hash_or_id : 0;
228 NameType get_name_type()
const {
return name_type_; }
233 void set_name(NameType
type,
const char *static_name,
uint32_t hash_or_id) {
234 if (
type == NameType::STATIC_STRING ||
type == NameType::SELF_POINTER) {
235 name_.static_name = static_name;
237 name_.hash_or_id = hash_or_id;
242 static bool cmp(SchedulerItem *a, SchedulerItem *b);
247 constexpr uint64_t get_next_execution()
const {
248 return (
static_cast<uint64_t
>(next_execution_high_) << 32) | next_execution_low_;
251 constexpr void set_next_execution(uint64_t value) {
252 next_execution_low_ =
static_cast<uint32_t>(value);
255 next_execution_high_ =
static_cast<uint16_t
>(value >> 32);
257 constexpr const char *get_type_str()
const {
return (
type == TIMEOUT) ?
"timeout" :
"interval"; }
260 Component *get_component()
const {
return name_type_ == NameType::SELF_POINTER ? nullptr :
component; }
261 const LogString *get_source()
const {
263 if (name_type_ == NameType::SELF_POINTER)
265 return component !=
nullptr ?
component->get_component_log_str() : LOG_STR(
"unknown");
272 void set_timer_common_(Component *
component, SchedulerItem::Type
type, NameType name_type,
const char *static_name,
274 const LogString *source =
nullptr);
285 uint64_t ESPHOME_ALWAYS_INLINE millis_64_from_(
uint32_t now) {
286#ifdef USE_NATIVE_64BIT_TIME
290 return Millis64Impl::compute(now);
301 inline bool ESPHOME_ALWAYS_INLINE HOT cleanup_() {
302 if (this->to_remove_empty_())
303 return !this->items_.empty();
304 return this->cleanup_slow_path_();
307 bool cleanup_slow_path_();
309 void process_to_add_slow_path_();
313 SchedulerItem *pop_raw_locked_();
316 SchedulerItem *get_item_from_pool_locked_();
321 void shrink_scheduler_vector_(std::vector<SchedulerItem *> *v);
329 bool cancel_item_locked_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
330 SchedulerItem::Type
type,
bool find_first =
false);
333 bool cancel_item_(Component *
component, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
334 SchedulerItem::Type
type);
337 inline bool HOT names_match_static_(
const char *name1,
const char *name2)
const {
342 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
348 inline bool HOT matches_item_locked_(SchedulerItem *item, Component *
component, NameType name_type,
349 const char *static_name,
uint32_t hash_or_id, SchedulerItem::Type
type,
350 bool skip_removed =
true)
const {
358 if (item->get_component() !=
component || item->type !=
type ||
359 (skip_removed && this->is_item_removed_locked_(item))) {
363 if (item->get_name_type() != name_type)
367 if (name_type == NameType::STATIC_STRING) {
368 return this->names_match_static_(item->get_name(), static_name);
370 if (name_type == NameType::SELF_POINTER) {
371 return item->name_.static_name == static_name;
373 return item->get_name_hash_or_id() == hash_or_id;
381 bool is_item_failed_(SchedulerItem *item)
const {
382 Component *
component = item->get_component();
387 bool should_skip_item_(SchedulerItem *item)
const {
return is_item_removed_(item) || this->is_item_failed_(item); }
395 void recycle_item_main_loop_(SchedulerItem *item);
398 void full_cleanup_removed_items_();
404#ifdef ESPHOME_DEBUG_SCHEDULER
406 void debug_log_timer_(
const SchedulerItem *item, NameType name_type,
const char *static_name,
uint32_t hash_or_id,
410#ifndef ESPHOME_THREAD_SINGLE
414 inline void ESPHOME_ALWAYS_INLINE HOT process_defer_queue_(
uint32_t &now) {
417 if (this->defer_empty_())
419 this->process_defer_queue_slow_path_(now);
423 void process_defer_queue_slow_path_(
uint32_t &now);
429 inline void cleanup_defer_queue_locked_() {
431 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
433 this->defer_queue_.clear();
437 this->compact_defer_queue_locked_();
439 this->defer_queue_front_ = 0;
445 void __attribute__((noinline)) compact_defer_queue_locked_();
452 bool is_item_removed_(SchedulerItem *item)
const {
453#ifdef ESPHOME_THREAD_MULTI_ATOMICS
455 return item->remove.load(std::memory_order_acquire);
467 bool is_item_removed_locked_(SchedulerItem *item)
const {
468#ifdef ESPHOME_THREAD_MULTI_ATOMICS
470 return item->remove.load(std::memory_order_relaxed);
480 void set_item_removed_(SchedulerItem *item,
bool removed) {
481#ifdef ESPHOME_THREAD_MULTI_ATOMICS
485 item->remove.store(removed ? 1 : 0, removed ? std::memory_order_release : std::memory_order_relaxed);
490 item->remove = removed;
503 inline size_t HOT mark_matching_items_removed_locked_(std::vector<SchedulerItem *> &container, Component *
component,
504 NameType name_type,
const char *static_name,
506 bool find_first =
false) {
507 if (container.empty())
509 return this->mark_matching_items_removed_slow_locked_(container,
component, name_type, static_name, hash_or_id,
515 __attribute__((noinline))
size_t mark_matching_items_removed_slow_locked_(std::vector<SchedulerItem *> &container,
516 Component *
component, NameType name_type,
517 const char *static_name,
519 SchedulerItem::Type
type,
bool find_first);
522 std::vector<SchedulerItem *> items_;
523 std::vector<SchedulerItem *> to_add_;
525#ifndef ESPHOME_THREAD_SINGLE
533#ifdef ESPHOME_THREAD_MULTI_ATOMICS
534 std::atomic<uint32_t> to_add_count_{0};
541 bool to_add_empty_()
const {
542#ifdef ESPHOME_THREAD_SINGLE
543 return this->to_add_.empty();
544#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
545 return this->to_add_count_.load(std::memory_order_relaxed) == 0;
547 return __atomic_load_n(&this->to_add_count_, __ATOMIC_RELAXED) == 0;
556 void to_add_count_increment_locked_() {
557#if defined(ESPHOME_THREAD_SINGLE)
559#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
560 this->to_add_count_.fetch_add(1, std::memory_order_relaxed);
562 uint32_t v = __atomic_load_n(&this->to_add_count_, __ATOMIC_RELAXED);
563 __atomic_store_n(&this->to_add_count_, v + 1, __ATOMIC_RELAXED);
568 void to_add_count_clear_locked_() {
569#if defined(ESPHOME_THREAD_SINGLE)
571#elif defined(ESPHOME_THREAD_MULTI_ATOMICS)
572 this->to_add_count_.store(0, std::memory_order_relaxed);
574 __atomic_store_n(&this->to_add_count_, 0, __ATOMIC_RELAXED);
578#ifndef ESPHOME_THREAD_SINGLE
582 std::vector<SchedulerItem *> defer_queue_;
583 size_t defer_queue_front_{0};
587#ifdef ESPHOME_THREAD_MULTI_ATOMICS
588 std::atomic<uint32_t> defer_count_{0};
593 bool defer_empty_()
const {
595#ifdef ESPHOME_THREAD_MULTI_ATOMICS
596 return this->defer_count_.load(std::memory_order_relaxed) == 0;
598 return __atomic_load_n(&this->defer_count_, __ATOMIC_RELAXED) == 0;
602 void defer_count_increment_locked_() {
603#ifdef ESPHOME_THREAD_MULTI_ATOMICS
604 this->defer_count_.fetch_add(1, std::memory_order_relaxed);
606 uint32_t v = __atomic_load_n(&this->defer_count_, __ATOMIC_RELAXED);
607 __atomic_store_n(&this->defer_count_, v + 1, __ATOMIC_RELAXED);
611 void defer_count_clear_locked_() {
612#ifdef ESPHOME_THREAD_MULTI_ATOMICS
613 this->defer_count_.store(0, std::memory_order_relaxed);
615 __atomic_store_n(&this->defer_count_, 0, __ATOMIC_RELAXED);
624#ifdef ESPHOME_THREAD_MULTI_ATOMICS
625 std::atomic<uint32_t> to_remove_{0};
631 bool to_remove_empty_()
const {
632#if defined(ESPHOME_THREAD_MULTI_ATOMICS)
633 return this->to_remove_.load(std::memory_order_relaxed) == 0;
634#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
635 return __atomic_load_n(&this->to_remove_, __ATOMIC_RELAXED) == 0;
637 return this->to_remove_ == 0;
641 void to_remove_add_locked_(
uint32_t count) {
642#if defined(ESPHOME_THREAD_MULTI_ATOMICS)
643 this->to_remove_.fetch_add(count, std::memory_order_relaxed);
644#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
645 uint32_t v = __atomic_load_n(&this->to_remove_, __ATOMIC_RELAXED);
646 __atomic_store_n(&this->to_remove_, v + count, __ATOMIC_RELAXED);
648 this->to_remove_ += count;
652 void to_remove_decrement_locked_() {
653#if defined(ESPHOME_THREAD_MULTI_ATOMICS)
654 this->to_remove_.fetch_sub(1, std::memory_order_relaxed);
655#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
656 uint32_t v = __atomic_load_n(&this->to_remove_, __ATOMIC_RELAXED);
657 __atomic_store_n(&this->to_remove_, v - 1, __ATOMIC_RELAXED);
663 void to_remove_clear_locked_() {
664#if defined(ESPHOME_THREAD_MULTI_ATOMICS)
665 this->to_remove_.store(0, std::memory_order_relaxed);
666#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
667 __atomic_store_n(&this->to_remove_, 0, __ATOMIC_RELAXED);
669 this->to_remove_ = 0;
674#if defined(ESPHOME_THREAD_MULTI_ATOMICS)
675 return this->to_remove_.load(std::memory_order_relaxed);
676#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS)
677 return __atomic_load_n(&this->to_remove_, __ATOMIC_RELAXED);
679 return this->to_remove_;
686 SchedulerItem *scheduler_item_pool_head_{
nullptr};
687 size_t scheduler_item_pool_size_{0};
689#ifdef ESPHOME_DEBUG_SCHEDULER
693 size_t debug_live_items_{0};
697 bool debug_verify_no_leak_()
const;
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
const Component * component
void delay(unsigned long ms)