mirror of
https://github.com/esphome/esphome.git
synced 2025-09-19 11:42:20 +01:00
Merge remote-tracking branch 'upstream/dev' into heap_scheduler_stress_component
This commit is contained in:
@@ -252,15 +252,17 @@ size_t SX127x::get_max_packet_size() {
|
||||
}
|
||||
}
|
||||
|
||||
void SX127x::transmit_packet(const std::vector<uint8_t> &packet) {
|
||||
SX127xError SX127x::transmit_packet(const std::vector<uint8_t> &packet) {
|
||||
if (this->payload_length_ > 0 && this->payload_length_ != packet.size()) {
|
||||
ESP_LOGE(TAG, "Packet size does not match config");
|
||||
return;
|
||||
return SX127xError::INVALID_PARAMS;
|
||||
}
|
||||
if (packet.empty() || packet.size() > this->get_max_packet_size()) {
|
||||
ESP_LOGE(TAG, "Packet size out of range");
|
||||
return;
|
||||
return SX127xError::INVALID_PARAMS;
|
||||
}
|
||||
|
||||
SX127xError ret = SX127xError::NONE;
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
this->set_mode_standby();
|
||||
if (this->payload_length_ == 0) {
|
||||
@@ -278,11 +280,13 @@ void SX127x::transmit_packet(const std::vector<uint8_t> &packet) {
|
||||
this->write_fifo_(packet);
|
||||
this->set_mode_tx();
|
||||
}
|
||||
|
||||
// wait until transmit completes, typically the delay will be less than 100 ms
|
||||
uint32_t start = millis();
|
||||
while (!this->dio0_pin_->digital_read()) {
|
||||
if (millis() - start > 4000) {
|
||||
ESP_LOGE(TAG, "Transmit packet failure");
|
||||
ret = SX127xError::TIMEOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -291,6 +295,7 @@ void SX127x::transmit_packet(const std::vector<uint8_t> &packet) {
|
||||
} else {
|
||||
this->set_mode_sleep();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SX127x::call_listeners_(const std::vector<uint8_t> &packet, float rssi, float snr) {
|
||||
@@ -335,13 +340,7 @@ void SX127x::loop() {
|
||||
}
|
||||
|
||||
void SX127x::run_image_cal() {
|
||||
uint32_t start = millis();
|
||||
uint8_t mode = this->read_register_(REG_OP_MODE);
|
||||
if ((mode & MODE_MASK) != MODE_STDBY) {
|
||||
ESP_LOGE(TAG, "Need to be in standby for image cal");
|
||||
return;
|
||||
}
|
||||
if (mode & MOD_LORA) {
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
this->set_mode_(MOD_FSK, MODE_SLEEP);
|
||||
this->set_mode_(MOD_FSK, MODE_STDBY);
|
||||
}
|
||||
@@ -350,13 +349,15 @@ void SX127x::run_image_cal() {
|
||||
} else {
|
||||
this->write_register_(REG_IMAGE_CAL, IMAGE_CAL_START);
|
||||
}
|
||||
uint32_t start = millis();
|
||||
while (this->read_register_(REG_IMAGE_CAL) & IMAGE_CAL_RUNNING) {
|
||||
if (millis() - start > 20) {
|
||||
ESP_LOGE(TAG, "Image cal failure");
|
||||
this->mark_failed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mode & MOD_LORA) {
|
||||
if (this->modulation_ == MOD_LORA) {
|
||||
this->set_mode_(this->modulation_, MODE_SLEEP);
|
||||
this->set_mode_(this->modulation_, MODE_STDBY);
|
||||
}
|
||||
@@ -375,6 +376,7 @@ void SX127x::set_mode_(uint8_t modulation, uint8_t mode) {
|
||||
}
|
||||
if (millis() - start > 20) {
|
||||
ESP_LOGE(TAG, "Set mode failure");
|
||||
this->mark_failed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,8 @@ enum SX127xBw : uint8_t {
|
||||
SX127X_BW_500_0,
|
||||
};
|
||||
|
||||
enum class SX127xError { NONE = 0, TIMEOUT, INVALID_PARAMS };
|
||||
|
||||
class SX127xListener {
|
||||
public:
|
||||
virtual void on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) = 0;
|
||||
@@ -79,7 +81,7 @@ class SX127x : public Component,
|
||||
void set_sync_value(const std::vector<uint8_t> &sync_value) { this->sync_value_ = sync_value; }
|
||||
void run_image_cal();
|
||||
void configure();
|
||||
void transmit_packet(const std::vector<uint8_t> &packet);
|
||||
SX127xError transmit_packet(const std::vector<uint8_t> &packet);
|
||||
void register_listener(SX127xListener *listener) { this->listeners_.push_back(listener); }
|
||||
Trigger<std::vector<uint8_t>, float, float> *get_packet_trigger() const { return this->packet_trigger_; };
|
||||
|
||||
|
@@ -255,11 +255,7 @@ void DeferredUpdateEventSourceList::on_client_disconnect_(DeferredUpdateEventSou
|
||||
}
|
||||
#endif
|
||||
|
||||
WebServer::WebServer(web_server_base::WebServerBase *base) : base_(base) {
|
||||
#ifdef USE_ESP32
|
||||
to_schedule_lock_ = xSemaphoreCreateMutex();
|
||||
#endif
|
||||
}
|
||||
WebServer::WebServer(web_server_base::WebServerBase *base) : base_(base) {}
|
||||
|
||||
#ifdef USE_WEBSERVER_CSS_INCLUDE
|
||||
void WebServer::set_css_include(const char *css_include) { this->css_include_ = css_include; }
|
||||
@@ -308,30 +304,7 @@ void WebServer::setup() {
|
||||
// getting a lot of events
|
||||
this->set_interval(10000, [this]() { this->events_.try_send_nodefer("", "ping", millis(), 30000); });
|
||||
}
|
||||
void WebServer::loop() {
|
||||
#ifdef USE_ESP32
|
||||
// Check atomic flag first to avoid taking semaphore when queue is empty
|
||||
if (this->to_schedule_has_items_.load(std::memory_order_relaxed) && xSemaphoreTake(this->to_schedule_lock_, 0L)) {
|
||||
std::function<void()> fn;
|
||||
if (!to_schedule_.empty()) {
|
||||
// scheduler execute things out of order which may lead to incorrect state
|
||||
// this->defer(std::move(to_schedule_.front()));
|
||||
// let's execute it directly from the loop
|
||||
fn = std::move(to_schedule_.front());
|
||||
to_schedule_.pop_front();
|
||||
if (to_schedule_.empty()) {
|
||||
this->to_schedule_has_items_.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(this->to_schedule_lock_);
|
||||
if (fn) {
|
||||
fn();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
this->events_.loop();
|
||||
}
|
||||
void WebServer::loop() { this->events_.loop(); }
|
||||
void WebServer::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Web Server:\n"
|
||||
@@ -526,13 +499,13 @@ void WebServer::handle_switch_request(AsyncWebServerRequest *request, const UrlM
|
||||
std::string data = this->switch_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method_equals("toggle")) {
|
||||
this->schedule_([obj]() { obj->toggle(); });
|
||||
this->defer([obj]() { obj->toggle(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("turn_on")) {
|
||||
this->schedule_([obj]() { obj->turn_on(); });
|
||||
this->defer([obj]() { obj->turn_on(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("turn_off")) {
|
||||
this->schedule_([obj]() { obj->turn_off(); });
|
||||
this->defer([obj]() { obj->turn_off(); });
|
||||
request->send(200);
|
||||
} else {
|
||||
request->send(404);
|
||||
@@ -568,7 +541,7 @@ void WebServer::handle_button_request(AsyncWebServerRequest *request, const UrlM
|
||||
std::string data = this->button_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method_equals("press")) {
|
||||
this->schedule_([obj]() { obj->press(); });
|
||||
this->defer([obj]() { obj->press(); });
|
||||
request->send(200);
|
||||
return;
|
||||
} else {
|
||||
@@ -648,7 +621,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
|
||||
std::string data = this->fan_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method_equals("toggle")) {
|
||||
this->schedule_([obj]() { obj->toggle().perform(); });
|
||||
this->defer([obj]() { obj->toggle().perform(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("turn_on") || match.method_equals("turn_off")) {
|
||||
auto call = match.method_equals("turn_on") ? obj->turn_on() : obj->turn_off();
|
||||
@@ -680,7 +653,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
} else {
|
||||
request->send(404);
|
||||
@@ -729,7 +702,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
|
||||
std::string data = this->light_json(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method_equals("toggle")) {
|
||||
this->schedule_([obj]() { obj->toggle().perform(); });
|
||||
this->defer([obj]() { obj->toggle().perform(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("turn_on")) {
|
||||
auto call = obj->turn_on();
|
||||
@@ -786,7 +759,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
|
||||
call.set_effect(effect);
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("turn_off")) {
|
||||
auto call = obj->turn_off();
|
||||
@@ -796,7 +769,7 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
|
||||
call.set_transition_length(*transition * 1000);
|
||||
}
|
||||
}
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
} else {
|
||||
request->send(404);
|
||||
@@ -881,7 +854,7 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
|
||||
}
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -939,7 +912,7 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM
|
||||
call.set_value(*value);
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1014,7 +987,7 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat
|
||||
call.set_date(value);
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1073,7 +1046,7 @@ void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMat
|
||||
call.set_time(value);
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1131,7 +1104,7 @@ void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const Ur
|
||||
call.set_datetime(value);
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1248,7 +1221,7 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM
|
||||
call.set_option(option.c_str()); // NOLINT
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1335,7 +1308,7 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
|
||||
call.set_target_temperature(*target_temperature);
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1452,13 +1425,13 @@ void WebServer::handle_lock_request(AsyncWebServerRequest *request, const UrlMat
|
||||
std::string data = this->lock_json(obj, obj->state, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
} else if (match.method_equals("lock")) {
|
||||
this->schedule_([obj]() { obj->lock(); });
|
||||
this->defer([obj]() { obj->lock(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("unlock")) {
|
||||
this->schedule_([obj]() { obj->unlock(); });
|
||||
this->defer([obj]() { obj->unlock(); });
|
||||
request->send(200);
|
||||
} else if (match.method_equals("open")) {
|
||||
this->schedule_([obj]() { obj->open(); });
|
||||
this->defer([obj]() { obj->open(); });
|
||||
request->send(200);
|
||||
} else {
|
||||
request->send(404);
|
||||
@@ -1529,7 +1502,7 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
|
||||
}
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1594,7 +1567,7 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
|
||||
return;
|
||||
}
|
||||
|
||||
this->schedule_([call]() mutable { call.perform(); });
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -1695,7 +1668,7 @@ void WebServer::handle_update_request(AsyncWebServerRequest *request, const UrlM
|
||||
return;
|
||||
}
|
||||
|
||||
this->schedule_([obj]() mutable { obj->perform(); });
|
||||
this->defer([obj]() mutable { obj->perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
@@ -2072,17 +2045,6 @@ void WebServer::add_sorting_group(uint64_t group_id, const std::string &group_na
|
||||
}
|
||||
#endif
|
||||
|
||||
void WebServer::schedule_(std::function<void()> &&f) {
|
||||
#ifdef USE_ESP32
|
||||
xSemaphoreTake(this->to_schedule_lock_, portMAX_DELAY);
|
||||
to_schedule_.push_back(std::move(f));
|
||||
this->to_schedule_has_items_.store(true, std::memory_order_relaxed);
|
||||
xSemaphoreGive(this->to_schedule_lock_);
|
||||
#else
|
||||
this->defer(std::move(f));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace web_server
|
||||
} // namespace esphome
|
||||
#endif
|
||||
|
@@ -14,12 +14,6 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#ifdef USE_ESP32
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <deque>
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
#if USE_WEBSERVER_VERSION >= 2
|
||||
extern const uint8_t ESPHOME_WEBSERVER_INDEX_HTML[] PROGMEM;
|
||||
@@ -504,7 +498,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||
|
||||
protected:
|
||||
void add_sorting_info_(JsonObject &root, EntityBase *entity);
|
||||
void schedule_(std::function<void()> &&f);
|
||||
web_server_base::WebServerBase *base_;
|
||||
#ifdef USE_ARDUINO
|
||||
DeferredUpdateEventSourceList events_;
|
||||
@@ -524,11 +517,6 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
||||
const char *js_include_{nullptr};
|
||||
#endif
|
||||
bool expose_log_{true};
|
||||
#ifdef USE_ESP32
|
||||
std::deque<std::function<void()>> to_schedule_;
|
||||
SemaphoreHandle_t to_schedule_lock_;
|
||||
std::atomic<bool> to_schedule_has_items_{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace web_server
|
||||
|
@@ -98,8 +98,6 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
||||
return;
|
||||
}
|
||||
|
||||
const auto now = this->millis_();
|
||||
|
||||
// Create and populate the scheduler item
|
||||
auto item = make_unique<SchedulerItem>();
|
||||
item->component = component;
|
||||
@@ -108,6 +106,19 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
|
||||
item->callback = std::move(func);
|
||||
item->remove = false;
|
||||
|
||||
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
||||
// Special handling for defer() (delay = 0, type = TIMEOUT)
|
||||
// ESP8266 and RP2040 are excluded because they don't need thread-safe defer handling
|
||||
if (delay == 0 && type == SchedulerItem::TIMEOUT) {
|
||||
// Put in defer queue for guaranteed FIFO execution
|
||||
LockGuard guard{this->lock_};
|
||||
this->defer_queue_.push_back(std::move(item));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto now = this->millis_();
|
||||
|
||||
// Type-specific setup
|
||||
if (type == SchedulerItem::INTERVAL) {
|
||||
item->interval = delay;
|
||||
@@ -244,6 +255,35 @@ optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
||||
return item->next_execution_ - now;
|
||||
}
|
||||
void HOT Scheduler::call() {
|
||||
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
||||
// Process defer queue first to guarantee FIFO execution order for deferred items.
|
||||
// Previously, defer() used the heap which gave undefined order for equal timestamps,
|
||||
// causing race conditions on multi-core systems (ESP32, BK7200).
|
||||
// With the defer queue:
|
||||
// - Deferred items (delay=0) go directly to defer_queue_ in set_timer_common_
|
||||
// - Items execute in exact order they were deferred (FIFO guarantee)
|
||||
// - No deferred items exist in to_add_, so processing order doesn't affect correctness
|
||||
// ESP8266 and RP2040 don't use this queue - they fall back to the heap-based approach
|
||||
// (ESP8266: single-core, RP2040: empty mutex implementation).
|
||||
while (!this->defer_queue_.empty()) {
|
||||
// The outer check is done without a lock for performance. If the queue
|
||||
// appears non-empty, we lock and process an item. We don't need to check
|
||||
// empty() again inside the lock because only this thread can remove items.
|
||||
std::unique_ptr<SchedulerItem> item;
|
||||
{
|
||||
LockGuard lock(this->lock_);
|
||||
item = std::move(this->defer_queue_.front());
|
||||
this->defer_queue_.pop_front();
|
||||
}
|
||||
|
||||
// Execute callback without holding lock to prevent deadlocks
|
||||
// if the callback tries to call defer() again
|
||||
if (!this->should_skip_item_(item.get())) {
|
||||
this->execute_item_(item.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto now = this->millis_();
|
||||
this->process_to_add();
|
||||
|
||||
@@ -317,8 +357,6 @@ void HOT Scheduler::call() {
|
||||
this->pop_raw_();
|
||||
continue;
|
||||
}
|
||||
App.set_current_component(item->component);
|
||||
|
||||
#ifdef ESPHOME_DEBUG_SCHEDULER
|
||||
const char *item_name = item->get_name();
|
||||
ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")",
|
||||
@@ -329,13 +367,7 @@ void HOT Scheduler::call() {
|
||||
// Warning: During callback(), a lot of stuff can happen, including:
|
||||
// - timeouts/intervals get added, potentially invalidating vector pointers
|
||||
// - timeouts/intervals get cancelled
|
||||
{
|
||||
uint32_t now_ms = millis();
|
||||
WarnIfComponentBlockingGuard guard{item->component, now_ms};
|
||||
item->callback();
|
||||
// Call finish to ensure blocking time is properly calculated and reported
|
||||
guard.finish();
|
||||
}
|
||||
this->execute_item_(item.get());
|
||||
}
|
||||
|
||||
{
|
||||
@@ -394,6 +426,26 @@ void HOT Scheduler::pop_raw_() {
|
||||
std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
||||
this->items_.pop_back();
|
||||
}
|
||||
// Helper function to check if item matches criteria for cancellation
|
||||
bool HOT Scheduler::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) {
|
||||
return false;
|
||||
}
|
||||
const char *item_name = item->get_name();
|
||||
return item_name != nullptr && strcmp(name_cstr, item_name) == 0;
|
||||
}
|
||||
|
||||
// Helper to execute a scheduler item
|
||||
void HOT Scheduler::execute_item_(SchedulerItem *item) {
|
||||
App.set_current_component(item->component);
|
||||
|
||||
uint32_t now_ms = millis();
|
||||
WarnIfComponentBlockingGuard guard{item->component, now_ms};
|
||||
item->callback();
|
||||
guard.finish();
|
||||
}
|
||||
|
||||
// Common implementation for cancel operations
|
||||
bool HOT Scheduler::cancel_item_(Component *component, bool is_static_string, const void *name_ptr,
|
||||
SchedulerItem::Type type) {
|
||||
@@ -410,6 +462,39 @@ bool HOT Scheduler::cancel_item_(Component *component, bool is_static_string, co
|
||||
return this->cancel_item_locked_(component, name_cstr, type);
|
||||
}
|
||||
|
||||
// Helper to cancel items by name - must be called with lock held
|
||||
bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_cstr, SchedulerItem::Type type) {
|
||||
bool ret = false;
|
||||
|
||||
// Check all containers for matching items
|
||||
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
||||
// Only check defer_queue_ on platforms that have it
|
||||
for (auto &item : this->defer_queue_) {
|
||||
if (this->matches_item_(item, component, name_cstr, type)) {
|
||||
item->remove = true;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto &item : this->items_) {
|
||||
if (this->matches_item_(item, component, name_cstr, type)) {
|
||||
item->remove = true;
|
||||
ret = true;
|
||||
this->to_remove_++; // Only track removals for heap items
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &item : this->to_add_) {
|
||||
if (this->matches_item_(item, component, name_cstr, type)) {
|
||||
item->remove = true;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t Scheduler::millis_() {
|
||||
// Get the current 32-bit millis value
|
||||
const uint32_t now = millis();
|
||||
|
@@ -3,6 +3,7 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
@@ -145,6 +146,19 @@ class Scheduler {
|
||||
// Common implementation for cancel operations
|
||||
bool cancel_item_(Component *component, bool is_static_string, const void *name_ptr, SchedulerItem::Type type);
|
||||
|
||||
private:
|
||||
// Helper functions for cancel operations
|
||||
bool matches_item_(const std::unique_ptr<SchedulerItem> &item, Component *component, const char *name_cstr,
|
||||
SchedulerItem::Type type);
|
||||
|
||||
// Helper to execute a scheduler item
|
||||
void execute_item_(SchedulerItem *item);
|
||||
|
||||
// Helper to check if item should be skipped
|
||||
bool should_skip_item_(const SchedulerItem *item) const {
|
||||
return item->remove || (item->component != nullptr && item->component->is_failed());
|
||||
}
|
||||
|
||||
bool empty_() {
|
||||
this->cleanup_();
|
||||
return this->items_.empty();
|
||||
@@ -153,6 +167,13 @@ class Scheduler {
|
||||
Mutex lock_;
|
||||
std::vector<std::unique_ptr<SchedulerItem>> items_;
|
||||
std::vector<std::unique_ptr<SchedulerItem>> to_add_;
|
||||
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
||||
// ESP8266 and RP2040 don't need the defer queue because:
|
||||
// ESP8266: Single-core with no preemptive multitasking
|
||||
// RP2040: Currently has empty mutex implementation in ESPHome
|
||||
// Both platforms save 40 bytes of RAM by excluding this
|
||||
std::deque<std::unique_ptr<SchedulerItem>> defer_queue_; // FIFO queue for defer() calls
|
||||
#endif
|
||||
uint32_t last_millis_{0};
|
||||
uint16_t millis_major_{0};
|
||||
uint32_t to_remove_{0};
|
||||
|
Reference in New Issue
Block a user