7#ifdef ESPHOME_THREAD_MULTI_ATOMICS
24 friend void ::esphome::retry_handler(
const std::shared_ptr<RetryArgs> &args);
29 template<
typename... Ts>
friend class DelayAction;
33 void set_timeout(Component *
component,
const std::string &name, uint32_t timeout, std::function<
void()> func);
45 void set_timeout(Component *
component,
const char *name, uint32_t timeout, std::function<
void()> func);
47 bool cancel_timeout(Component *
component,
const std::string &name);
48 bool cancel_timeout(Component *
component,
const char *name);
50 void set_interval(Component *
component,
const std::string &name, uint32_t interval, std::function<
void()> func);
62 void set_interval(Component *
component,
const char *name, uint32_t interval, std::function<
void()> func);
64 bool cancel_interval(Component *
component,
const std::string &name);
65 bool cancel_interval(Component *
component,
const char *name);
66 void set_retry(Component *
component,
const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
67 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
68 void set_retry(Component *
component,
const char *name, uint32_t initial_wait_time, uint8_t max_attempts,
69 std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor = 1.0f);
70 bool cancel_retry(Component *
component,
const std::string &name);
71 bool cancel_retry(Component *
component,
const char *name);
78 optional<uint32_t> next_schedule_in(uint32_t now);
82 void call(uint32_t now);
84 void process_to_add();
87 struct SchedulerItem {
92 const char *static_name;
104 std::function<void()> callback;
105 uint16_t next_execution_high_;
107#ifdef ESPHOME_THREAD_MULTI_ATOMICS
110 std::atomic<bool> remove{
false};
113 enum Type : uint8_t {
TIMEOUT, INTERVAL }
type : 1;
114 bool name_is_dynamic : 1;
120 enum Type : uint8_t {
TIMEOUT, INTERVAL }
type : 1;
122 bool name_is_dynamic : 1;
131 next_execution_low_(0),
132 next_execution_high_(0),
133#ifdef ESPHOME_THREAD_MULTI_ATOMICS
136 name_is_dynamic(false),
141 name_is_dynamic(
false),
144 name_.static_name =
nullptr;
148 ~SchedulerItem() { clear_dynamic_name(); }
151 SchedulerItem(
const SchedulerItem &) =
delete;
152 SchedulerItem &operator=(
const SchedulerItem &) =
delete;
155 SchedulerItem(SchedulerItem &&) =
delete;
156 SchedulerItem &operator=(SchedulerItem &&) =
delete;
159 const char *get_name()
const {
return name_is_dynamic ? name_.dynamic_name : name_.static_name; }
162 void clear_dynamic_name() {
163 if (name_is_dynamic && name_.dynamic_name) {
164 delete[] name_.dynamic_name;
165 name_.dynamic_name =
nullptr;
166 name_is_dynamic =
false;
171 void set_name(
const char *name,
bool make_copy =
false) {
173 clear_dynamic_name();
177 name_.static_name =
nullptr;
178 }
else if (make_copy) {
180 size_t len = strlen(name);
181 name_.dynamic_name =
new char[
len + 1];
182 memcpy(name_.dynamic_name, name,
len + 1);
183 name_is_dynamic =
true;
186 name_.static_name = name;
190 static bool cmp(
const std::unique_ptr<SchedulerItem> &a,
const std::unique_ptr<SchedulerItem> &b);
195 constexpr uint64_t get_next_execution()
const {
196 return (
static_cast<uint64_t
>(next_execution_high_) << 32) | next_execution_low_;
199 constexpr void set_next_execution(uint64_t value) {
200 next_execution_low_ =
static_cast<uint32_t>(value);
203 next_execution_high_ =
static_cast<uint16_t
>(value >> 32);
205 constexpr const char *get_type_str()
const {
return (
type == TIMEOUT) ?
"timeout" :
"interval"; }
206 const LogString *get_source()
const {
return component ?
component->get_component_log_str() : LOG_STR(
"unknown"); }
210 void set_timer_common_(Component *
component, SchedulerItem::Type
type,
bool is_static_string,
const void *name_ptr,
211 uint32_t delay, std::function<
void()> func,
bool is_retry =
false,
bool skip_cancel =
false);
214 void set_retry_common_(Component *
component,
bool is_static_string,
const void *name_ptr, uint32_t initial_wait_time,
215 uint8_t max_attempts, std::function<
RetryResult(uint8_t)> func,
float backoff_increase_factor);
217 uint64_t millis_64_(uint32_t now);
224 std::unique_ptr<SchedulerItem> pop_raw_locked_();
228 bool cancel_item_locked_(Component *
component,
const char *name, SchedulerItem::Type
type,
bool match_retry =
false);
231 inline const char *get_name_cstr_(
bool is_static_string,
const void *name_ptr) {
232 return is_static_string ?
static_cast<const char *
>(name_ptr) : static_cast<const std::string *>(name_ptr)->c_str();
236 bool cancel_item_(Component *
component,
bool is_static_string,
const void *name_ptr, SchedulerItem::Type
type);
239 inline bool HOT names_match_(
const char *name1,
const char *name2)
const {
244 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
249 inline bool HOT matches_item_locked_(
const std::unique_ptr<SchedulerItem> &item, Component *
component,
250 const char *name_cstr, SchedulerItem::Type
type,
bool match_retry,
251 bool skip_removed =
true)
const {
260 if (item->component !=
component || item->type !=
type || (skip_removed && item->remove) ||
261 (match_retry && !item->is_retry)) {
264 return this->names_match_(item->get_name(), name_cstr);
268 uint32_t execute_item_(SchedulerItem *item, uint32_t now);
271 bool should_skip_item_(SchedulerItem *item)
const {
272 return is_item_removed_(item) || (item->component !=
nullptr && item->component->is_failed());
276 void recycle_item_(std::unique_ptr<SchedulerItem> item);
279 void full_cleanup_removed_items_();
281#ifdef ESPHOME_DEBUG_SCHEDULER
283 void debug_log_timer_(
const SchedulerItem *item,
bool is_static_string,
const char *name_cstr,
284 SchedulerItem::Type
type, uint32_t delay, uint64_t now);
287#ifndef ESPHOME_THREAD_SINGLE
289 inline void process_defer_queue_(uint32_t &now) {
310 size_t defer_queue_end = this->defer_queue_.size();
312 while (this->defer_queue_front_ < defer_queue_end) {
313 std::unique_ptr<SchedulerItem> item;
315 LockGuard lock(this->lock_);
322 item = std::move(this->defer_queue_[this->defer_queue_front_]);
323 this->defer_queue_front_++;
328 if (!this->should_skip_item_(item.get())) {
329 now = this->execute_item_(item.get(), now);
332 this->recycle_item_(std::move(item));
337 if (this->defer_queue_front_ >= defer_queue_end) {
338 LockGuard lock(this->lock_);
339 this->cleanup_defer_queue_locked_();
345 inline void cleanup_defer_queue_locked_() {
347 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
349 this->defer_queue_.clear();
362 size_t remaining = this->defer_queue_.size() - this->defer_queue_front_;
363 for (
size_t i = 0; i < remaining; i++) {
364 this->defer_queue_[i] = std::move(this->defer_queue_[this->defer_queue_front_ + i]);
366 this->defer_queue_.resize(remaining);
368 this->defer_queue_front_ = 0;
376 bool is_item_removed_(SchedulerItem *item)
const {
377#ifdef ESPHOME_THREAD_MULTI_ATOMICS
379 return item->remove.load(std::memory_order_acquire);
392 void set_item_removed_(SchedulerItem *item,
bool removed) {
393#ifdef ESPHOME_THREAD_MULTI_ATOMICS
397 item->remove.store(removed, removed ? std::memory_order_release : std::memory_order_relaxed);
402 item->remove = removed;
409 template<
typename Container>
410 size_t mark_matching_items_removed_locked_(Container &container, Component *
component,
const char *name_cstr,
411 SchedulerItem::Type
type,
bool match_retry) {
413 for (
auto &item : container) {
420 if (this->matches_item_locked_(item,
component, name_cstr,
type, match_retry)) {
422 this->set_item_removed_(item.get(),
true);
431 template<
typename Container>
432 bool has_cancelled_timeout_in_container_locked_(
const Container &container, Component *
component,
433 const char *name_cstr,
bool match_retry)
const {
434 for (
const auto &item : container) {
441 if (is_item_removed_(item.get()) &&
442 this->matches_item_locked_(item,
component, name_cstr, SchedulerItem::TIMEOUT, match_retry,
451 std::vector<std::unique_ptr<SchedulerItem>> items_;
452 std::vector<std::unique_ptr<SchedulerItem>> to_add_;
453#ifndef ESPHOME_THREAD_SINGLE
457 std::vector<std::unique_ptr<SchedulerItem>> defer_queue_;
458 size_t defer_queue_front_{0};
470 std::vector<std::unique_ptr<SchedulerItem>> scheduler_item_pool_;
472#ifdef ESPHOME_THREAD_MULTI_ATOMICS
483 std::atomic<uint32_t> last_millis_{0};
495#ifdef ESPHOME_THREAD_MULTI_ATOMICS
496 std::atomic<uint16_t> millis_major_{0};
498 uint16_t millis_major_{0};
const Component * component
Providing packet encoding functions for exchanging data with a remote host.
void retry_handler(const std::shared_ptr< RetryArgs > &args)