Pause the SCGI listener for a second when accept() runs out of descriptors or memory, instead of throwing.

This commit is contained in:
Silas Mariusz
2026-10-21 06:07:31 +00:00
committed by Jari Sundell
parent 40658e20d9
commit 8df6f23e77
2 changed files with 36 additions and 1 deletions
+31 -1
View File
@@ -10,6 +10,8 @@
#include <torrent/net/fd.h>
#include <torrent/net/socket_address.h>
#include <torrent/system/poll.h>
#include <torrent/system/scheduler.h>
#include <torrent/utils/log.h>
#include <torrent/runtime/socket_manager.h>
#include "control.h"
@@ -25,6 +27,8 @@ SCgi::SCgi() {
std::generate(m_tasks.begin(), m_tasks.end(), []() { return std::make_unique<SCgiTask>(); });
m_current = m_tasks.begin();
m_resume_accept.slot() = [this] { resume_accept(); };
}
SCgi::~SCgi() {
@@ -121,6 +125,9 @@ SCgi::stop() {
if (!is_open())
return;
if (m_resume_accept.is_scheduled())
torrent::this_thread::scheduler()->erase(&m_resume_accept);
for (auto& itr : m_tasks) {
if (itr->is_open())
itr->close();
@@ -158,9 +165,16 @@ SCgi::event_read() {
return;
// Force a new event_read() call just to be sure we don't enter an infinite loop.
if (errno == ECONNABORTED)
if (errno == ECONNABORTED || errno == EPROTO || errno == EPERM)
return;
// Out of file descriptors or memory: the connection stays queued and the socket stays readable,
// so stop reading it for a while instead of spinning.
if (errno == EMFILE || errno == ENFILE || errno == ENOBUFS || errno == ENOMEM) {
pause_accept(errno);
return;
}
throw torrent::resource_error("Listener port accept() failed: " + std::string(std::strerror(errno)));
}
@@ -189,6 +203,22 @@ SCgi::event_read() {
}
}
void
SCgi::pause_accept(int error) {
lt_log_print(torrent::LOG_ERRORS, "scgi: accept() failed: %s : not accepting connections for a second", std::strerror(error));
torrent::this_thread::poll()->remove_read(this);
torrent::this_thread::scheduler()->update_wait_for(&m_resume_accept, std::chrono::seconds(1));
}
void
SCgi::resume_accept() {
if (!is_open())
return;
torrent::this_thread::poll()->insert_read(this);
}
void
SCgi::event_write() {
throw torrent::internal_error("Listener does not support write().");
+5
View File
@@ -4,6 +4,7 @@
#include <array>
#include <memory>
#include <torrent/system/event.h>
#include <torrent/system/scheduler.h>
#include "rpc/scgi_task.h"
@@ -39,12 +40,16 @@ private:
using task_list = std::array<std::unique_ptr<SCgiTask>, max_tasks>;
void open(sockaddr* sa, unsigned int length);
void pause_accept(int error);
void resume_accept();
std::string m_path;
int m_logFd{-1};
task_list m_tasks;
task_list::iterator m_current;
torrent::system::SchedulerEntry m_resume_accept;
};
}