mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-21 16:46:18 +00:00
Pause the SCGI listener for a second when accept() runs out of descriptors or memory, instead of throwing.
This commit is contained in:
committed by
Jari Sundell
parent
40658e20d9
commit
8df6f23e77
+31
-1
@@ -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().");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user