mirror of
https://github.com/esphome/esphome.git
synced 2026-09-02 11:06:04 +00:00
[web_server_idf] Move session adoption to out-of-line cold path
Keep the hot path in AsyncEventSource::loop() to the atomic load, branch, and dead-session cleanup. On a real connect, call a noinline+cold helper (adopt_pending_sessions_main_loop_) to swap the pending list out, drop any already-disconnected sessions, and invoke on_connect_ / start_session_main_loop_ on the rest.
This commit is contained in:
@@ -493,26 +493,9 @@ void AsyncEventSource::handleRequest(AsyncWebServerRequest *request) {
|
||||
}
|
||||
|
||||
bool AsyncEventSource::loop() {
|
||||
// Fast path: one atomic load per tick. Lock only on a real connect.
|
||||
// Fast path: one atomic load per tick. Slow path is out-of-line on connect.
|
||||
if (this->has_pending_sessions_.load(std::memory_order_acquire)) {
|
||||
std::vector<AsyncEventSourceResponse *> incoming;
|
||||
{
|
||||
LockGuard guard{this->pending_mutex_};
|
||||
incoming.swap(this->pending_sessions_);
|
||||
this->has_pending_sessions_.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
for (auto *rsp : incoming) {
|
||||
// Already disconnected? Drop it; skip on_connect_/prime on a dead session.
|
||||
if (rsp->fd_.load() == 0) {
|
||||
delete rsp; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
continue;
|
||||
}
|
||||
this->sessions_.push_back(rsp);
|
||||
if (this->on_connect_) {
|
||||
this->on_connect_(rsp);
|
||||
}
|
||||
rsp->start_session_main_loop_();
|
||||
}
|
||||
this->adopt_pending_sessions_main_loop_();
|
||||
}
|
||||
|
||||
// Clean up dead sessions safely
|
||||
@@ -535,6 +518,27 @@ bool AsyncEventSource::loop() {
|
||||
return !this->sessions_.empty();
|
||||
}
|
||||
|
||||
void AsyncEventSource::adopt_pending_sessions_main_loop_() {
|
||||
std::vector<AsyncEventSourceResponse *> incoming;
|
||||
{
|
||||
LockGuard guard{this->pending_mutex_};
|
||||
incoming.swap(this->pending_sessions_);
|
||||
this->has_pending_sessions_.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
for (auto *rsp : incoming) {
|
||||
// Already disconnected? Drop it; skip on_connect_/session start on a dead session.
|
||||
if (rsp->fd_.load() == 0) {
|
||||
delete rsp; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
continue;
|
||||
}
|
||||
this->sessions_.push_back(rsp);
|
||||
if (this->on_connect_) {
|
||||
this->on_connect_(rsp);
|
||||
}
|
||||
rsp->start_session_main_loop_();
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncEventSource::try_send_nodefer(const char *message, const char *event, uint32_t id, uint32_t reconnect) {
|
||||
for (auto *ses : this->sessions_) {
|
||||
if (ses->fd_.load() != 0) { // Skip dead sessions
|
||||
|
||||
@@ -350,6 +350,9 @@ class AsyncEventSource : public AsyncWebHandler {
|
||||
size_t count() const { return this->sessions_.size(); }
|
||||
|
||||
protected:
|
||||
// Cold path: move sessions from pending_sessions_ into sessions_ and greet each one.
|
||||
void __attribute__((noinline, cold)) adopt_pending_sessions_main_loop_();
|
||||
|
||||
std::string url_;
|
||||
// Main-loop only. Vector: SSE sessions are 1-5 connections, linear search beats set.
|
||||
std::vector<AsyncEventSourceResponse *> sessions_;
|
||||
|
||||
Reference in New Issue
Block a user