1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-04 04:12:23 +01:00

[scheduler] Fix retry race condition on cancellation (#9788)

This commit is contained in:
J. Nick Koston
2025-07-25 08:14:15 -10:00
committed by GitHub
parent 9ac10d7276
commit 88ccde4ba1
4 changed files with 104 additions and 33 deletions

View File

@@ -15,8 +15,15 @@
namespace esphome {
class Component;
struct RetryArgs;
// Forward declaration of retry_handler - needs to be non-static for friend declaration
void retry_handler(const std::shared_ptr<RetryArgs> &args);
class Scheduler {
// Allow retry_handler to access protected members
friend void ::esphome::retry_handler(const std::shared_ptr<RetryArgs> &args);
public:
// Public API - accepts std::string for backward compatibility
void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> func);
@@ -147,7 +154,7 @@ class Scheduler {
// Common implementation for both timeout and interval
void set_timer_common_(Component *component, SchedulerItem::Type type, bool is_static_string, const void *name_ptr,
uint32_t delay, std::function<void()> func);
uint32_t delay, std::function<void()> func, bool is_retry = false);
uint64_t millis_64_(uint32_t now);
// Cleanup logically deleted items from the scheduler
@@ -170,8 +177,8 @@ class Scheduler {
// Helper function to check if item matches criteria for cancellation
inline bool HOT matches_item_(const std::unique_ptr<SchedulerItem> &item, Component *component, const char *name_cstr,
SchedulerItem::Type type) {
if (item->component != component || item->type != type || item->remove) {
SchedulerItem::Type type, bool skip_removed = true) const {
if (item->component != component || item->type != type || (skip_removed && item->remove)) {
return false;
}
const char *item_name = item->get_name();
@@ -197,6 +204,18 @@ class Scheduler {
return item->remove || (item->component != nullptr && item->component->is_failed());
}
// Template helper to check if any item in a container matches our criteria
template<typename Container>
bool has_cancelled_timeout_in_container_(const Container &container, Component *component,
const char *name_cstr) const {
for (const auto &item : container) {
if (item->remove && this->matches_item_(item, component, name_cstr, SchedulerItem::TIMEOUT, false)) {
return true;
}
}
return false;
}
Mutex lock_;
std::vector<std::unique_ptr<SchedulerItem>> items_;
std::vector<std::unique_ptr<SchedulerItem>> to_add_;