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);
226 bool cancel_item_locked_(Component *
component,
const char *name, SchedulerItem::Type
type,
bool match_retry =
false);
229 inline const char *get_name_cstr_(
bool is_static_string,
const void *name_ptr) {
230 return is_static_string ?
static_cast<const char *
>(name_ptr) : static_cast<const std::string *>(name_ptr)->c_str();
234 bool cancel_item_(Component *
component,
bool is_static_string,
const void *name_ptr, SchedulerItem::Type
type);
237 inline bool HOT names_match_(
const char *name1,
const char *name2)
const {
242 return (name1 !=
nullptr && name2 !=
nullptr) && ((name1 == name2) || (strcmp(name1, name2) == 0));
246 inline bool HOT matches_item_(
const std::unique_ptr<SchedulerItem> &item, Component *
component,
const char *name_cstr,
247 SchedulerItem::Type
type,
bool match_retry,
bool skip_removed =
true)
const {
248 if (item->component !=
component || item->type !=
type || (skip_removed && item->remove) ||
249 (match_retry && !item->is_retry)) {
252 return this->names_match_(item->get_name(), name_cstr);
256 uint32_t execute_item_(SchedulerItem *item, uint32_t now);
259 bool should_skip_item_(SchedulerItem *item)
const {
260 return is_item_removed_(item) || (item->component !=
nullptr && item->component->is_failed());
264 void recycle_item_(std::unique_ptr<SchedulerItem> item);
267 void full_cleanup_removed_items_();
269#ifdef ESPHOME_DEBUG_SCHEDULER
271 void debug_log_timer_(
const SchedulerItem *item,
bool is_static_string,
const char *name_cstr,
272 SchedulerItem::Type
type, uint32_t delay, uint64_t now);
275#ifndef ESPHOME_THREAD_SINGLE
277 inline void process_defer_queue_(uint32_t &now) {
298 size_t defer_queue_end = this->defer_queue_.size();
300 while (this->defer_queue_front_ < defer_queue_end) {
301 std::unique_ptr<SchedulerItem> item;
303 LockGuard lock(this->lock_);
310 item = std::move(this->defer_queue_[this->defer_queue_front_]);
311 this->defer_queue_front_++;
316 if (!this->should_skip_item_(item.get())) {
317 now = this->execute_item_(item.get(), now);
320 this->recycle_item_(std::move(item));
325 if (this->defer_queue_front_ >= defer_queue_end) {
326 LockGuard lock(this->lock_);
327 this->cleanup_defer_queue_locked_();
333 inline void cleanup_defer_queue_locked_() {
335 if (this->defer_queue_front_ >= this->defer_queue_.size()) {
337 this->defer_queue_.clear();
350 size_t remaining = this->defer_queue_.size() - this->defer_queue_front_;
351 for (
size_t i = 0; i < remaining; i++) {
352 this->defer_queue_[i] = std::move(this->defer_queue_[this->defer_queue_front_ + i]);
354 this->defer_queue_.resize(remaining);
356 this->defer_queue_front_ = 0;
364 bool is_item_removed_(SchedulerItem *item)
const {
365#ifdef ESPHOME_THREAD_MULTI_ATOMICS
367 return item->remove.load(std::memory_order_acquire);
380 void set_item_removed_(SchedulerItem *item,
bool removed) {
381#ifdef ESPHOME_THREAD_MULTI_ATOMICS
385 item->remove.store(removed, removed ? std::memory_order_release : std::memory_order_relaxed);
390 item->remove = removed;
397 template<
typename Container>
398 size_t mark_matching_items_removed_(Container &container, Component *
component,
const char *name_cstr,
399 SchedulerItem::Type
type,
bool match_retry) {
401 for (
auto &item : container) {
408 if (this->matches_item_(item,
component, name_cstr,
type, match_retry)) {
410 this->set_item_removed_(item.get(),
true);
418 template<
typename Container>
419 bool has_cancelled_timeout_in_container_(
const Container &container, Component *
component,
const char *name_cstr,
420 bool match_retry)
const {
421 for (
const auto &item : container) {
428 if (is_item_removed_(item.get()) &&
429 this->matches_item_(item,
component, name_cstr, SchedulerItem::TIMEOUT, match_retry,
438 std::vector<std::unique_ptr<SchedulerItem>> items_;
439 std::vector<std::unique_ptr<SchedulerItem>> to_add_;
440#ifndef ESPHOME_THREAD_SINGLE
444 std::vector<std::unique_ptr<SchedulerItem>> defer_queue_;
445 size_t defer_queue_front_{0};
457 std::vector<std::unique_ptr<SchedulerItem>> scheduler_item_pool_;
459#ifdef ESPHOME_THREAD_MULTI_ATOMICS
470 std::atomic<uint32_t> last_millis_{0};
482#ifdef ESPHOME_THREAD_MULTI_ATOMICS
483 std::atomic<uint16_t> millis_major_{0};
485 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)