Replace ThreadWorker with scgi::ThreadScgi.

This commit is contained in:
Jari Sundell
2025-12-17 23:43:43 +01:00
committed by GitHub
parent 8f644e65dd
commit 5dbb0020dc
13 changed files with 218 additions and 150 deletions
+4 -3
View File
@@ -125,6 +125,9 @@ libsub_root_a_SOURCES = \
rpc/tinyxml2/tinyxml2.cc \
rpc/nlohmann/json.h \
\
scgi/thread_scgi.cc \
scgi/thread_scgi.h \
\
session/session_manager.cc \
session/session_manager.h \
session/thread_session.cc \
@@ -195,9 +198,7 @@ libsub_root_a_SOURCES = \
option_parser.cc \
option_parser.h \
signal_handler.cc \
signal_handler.h \
thread_worker.cc \
thread_worker.h
signal_handler.h
AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -DPACKAGE_DATADIR=\"$(pkgdatadir)\"
-1
View File
@@ -185,7 +185,6 @@ cmd_file_append(const torrent::Object::list_type& args) {
void
initialize_command_local() {
core::DownloadList* dList = control->core()->download_list();
core::DownloadStore* dStore = control->core()->download_store();
torrent::ChunkManager* chunkManager = torrent::chunk_manager();
torrent::FileManager* fileManager = torrent::file_manager();
+7 -7
View File
@@ -11,7 +11,6 @@
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "thread_worker.h"
#include "core/download.h"
#include "core/download_list.h"
#include "core/manager.h"
@@ -135,12 +134,13 @@ initialize_command_logging() {
CMD2_ANY_LIST ("log.append_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_LIST ("log.append_gz_file", std::bind(&apply_log_open, log_flag_append_file, std::placeholders::_2));
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
CMD2_ANY_STRING_V("log.close", std::bind(&torrent::log_close_output_str, std::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
CMD2_ANY_LIST ("log.add_output", std::bind(&apply_log_add_output, std::placeholders::_2));
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
CMD2_ANY_STRING_V("log.rpc", std::bind(&ThreadWorker::set_rpc_log, worker_thread, std::placeholders::_2));
CMD2_REDIRECT ("log.xmlrpc", "log.rpc"); // For backwards compatibility
CMD2_ANY_STRING ("log.execute", std::bind(&apply_log, std::placeholders::_2, 0));
CMD2_ANY_STRING ("log.vmmap.dump", std::bind(&log_vmmap_dump, std::placeholders::_2));
CMD2_ANY_STRING_V("log.rpc", [](const auto&, const auto& str) { scgi_thread::set_rpc_log(str); });
CMD2_REDIRECT ("log.xmlrpc", "log.rpc"); // For backwards compatibility
}
+2 -3
View File
@@ -20,7 +20,6 @@
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "thread_worker.h"
#include "core/download.h"
#include "core/manager.h"
#include "rpc/scgi.h"
@@ -79,7 +78,7 @@ initialize_rpc_handlers() {
torrent::Object
apply_scgi(const std::string& arg, int type) {
if (worker_thread->scgi() != NULL)
if (scgi_thread::scgi() != nullptr)
throw torrent::input_error("SCGI already enabled.");
initialize_rpc_handlers();
@@ -142,7 +141,7 @@ apply_scgi(const std::string& arg, int type) {
throw torrent::input_error(e.what());
}
worker_thread->set_scgi(scgi);
scgi_thread::set_scgi(scgi);
return torrent::Object();
}
+8 -9
View File
@@ -8,7 +8,6 @@
#include <torrent/net/network_manager.h>
#include <torrent/utils/directory_events.h>
#include "thread_worker.h"
#include "core/dht_manager.h"
#include "core/download_store.h"
#include "core/http_queue.h"
@@ -63,7 +62,7 @@ Control::initialize() {
session_thread::manager()->start();
session_thread::thread()->start_thread();
worker_thread->start_thread();
scgi_thread::thread()->start_thread();
display::Canvas::initialize();
display::Window::slot_schedule([this](display::Window* w, std::chrono::microseconds t) { m_display->schedule(w, t); });
@@ -90,6 +89,9 @@ Control::cleanup() {
if(!display::Canvas::daemon())
m_inputStdin->remove(torrent::this_thread::poll());
if (scgi_thread::thread()->is_active())
scgi_thread::thread()->stop_thread_wait();
// Wait for all session files to be written.
session_thread::thread()->stop_thread_wait();
@@ -109,7 +111,7 @@ Control::cleanup_exception() {
bool
Control::is_shutdown_completed() {
if (!m_shutdownQuick || worker_thread->is_active())
if (!m_shutdownQuick)
return false;
// Tracker requests can be disowned, so wait for these to
@@ -128,10 +130,10 @@ void
Control::handle_shutdown() {
rpc::commands.call_catch("event.system.shutdown", rpc::make_target(), "shutdown", "System shutdown event action failed: ");
if (!m_shutdownQuick) {
if (worker_thread->is_active())
worker_thread->stop_thread_wait();
if (scgi_thread::thread()->is_active())
scgi_thread::thread()->stop_thread_wait();
if (!m_shutdownQuick) {
torrent::runtime::network_manager()->listen_close();
m_directory_events->close();
@@ -141,9 +143,6 @@ Control::handle_shutdown() {
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_shutdown, 5s);
} else {
if (worker_thread->is_active())
worker_thread->stop_thread_wait();
m_core->shutdown(true);
}
-1
View File
@@ -5,4 +5,3 @@
rpc::ip_table_list ip_tables;
Control* control{};
ThreadWorker* worker_thread{};
+18 -5
View File
@@ -6,20 +6,33 @@
#include "rpc/ip_table_list.h"
class Control;
class ThreadWorker;
extern rpc::ip_table_list ip_tables;
extern Control* control;
// TODO: Update to new thread model.
extern ThreadWorker* worker_thread;
namespace rpc {
class SCgi;
}
namespace session {
class SessionManager;
}
} // namespace session
namespace scgi_thread {
torrent::utils::Thread* thread();
std::thread::id thread_id();
void callback(void* target, std::function<void ()>&& fn);
void cancel_callback(void* target);
void cancel_callback_and_wait(void* target);
rpc::SCgi* scgi();
void set_scgi(rpc::SCgi* scgi);
void set_rpc_log(const std::string& filename);
} // namespace torrent::scgi_thread
namespace session_thread {
+3 -9
View File
@@ -31,6 +31,7 @@
#include "rpc/command_scheduler.h"
#include "rpc/command_scheduler_item.h"
#include "rpc/parse_commands.h"
#include "scgi/thread_scgi.h"
#include "session/thread_session.h"
#include "ui/root.h"
#include "utils/directory.h"
@@ -41,8 +42,6 @@
#include "signal_handler.h"
#include "option_parser.h"
#include "thread_worker.h"
#define LT_LOG(log_fmt, ...) \
lt_log_print(torrent::LOG_SYSTEM, "system: " log_fmt, __VA_ARGS__);
@@ -215,12 +214,9 @@ main(int argc, char** argv) {
torrent::initialize();
torrent::set_main_thread_slots(std::bind(&client_perform));
scgi::ThreadScgi::create_thread();
session::ThreadSession::create_thread();
// TODO: Move to controller.
worker_thread = new ThreadWorker();
worker_thread->init_thread();
// Initialize option handlers after libtorrent to ensure
// torrent::ConnectionManager* are valid etc.
initialize_commands();
@@ -535,11 +531,9 @@ main(int argc, char** argv) {
delete control;
control = nullptr;
scgi::ThreadScgi::destroy_thread();
session::ThreadSession::destroy_thread();
delete worker_thread;
worker_thread = nullptr;
torrent::log_cleanup();
return 0;
+2 -3
View File
@@ -11,7 +11,6 @@
#include "control.h"
#include "globals.h"
#include "thread_worker.h"
#include "rpc/scgi_task.h"
#include "utils/socket_fd.h"
@@ -93,7 +92,7 @@ SCgi::open(void* sa, unsigned int length) {
void
SCgi::activate() {
assert(std::this_thread::get_id() == worker_thread->thread_id() && "SCgi::activate() must be called from the worker thread.");
assert(torrent::this_thread::thread() == scgi_thread::thread());
torrent::this_thread::poll()->open(this);
torrent::this_thread::poll()->insert_read(this);
@@ -102,7 +101,7 @@ SCgi::activate() {
void
SCgi::deactivate() {
assert(std::this_thread::get_id() == worker_thread->thread_id() && "SCgi::deactivate() must be called from the worker thread.");
assert(torrent::this_thread::thread() == scgi_thread::thread());
torrent::this_thread::poll()->remove_and_close(this);
}
+143
View File
@@ -0,0 +1,143 @@
#include "config.h"
#include "scgi/thread_scgi.h"
#include <fcntl.h>
#include <unistd.h>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include <torrent/utils/log.h>
#include "rpc/scgi.h"
namespace scgi {
class ThreadScgiInternal {
public:
static ThreadScgi* thread_scgi() { return ThreadScgi::internal_thread_scgi(); }
};
ThreadScgi* ThreadScgi::m_thread_scgi{};
void
ThreadScgi::create_thread() {
auto thread = new ThreadScgi;
m_thread_scgi = thread;
m_thread_scgi->m_state = STATE_INITIALIZED;
}
void
ThreadScgi::destroy_thread() {
delete m_thread_scgi;
m_thread_scgi = nullptr;
}
ThreadScgi*
ThreadScgi::thread_scgi() {
return m_thread_scgi;
}
// TODO: Remove '= 0'.
void
ThreadScgi::init_thread() {
}
void
ThreadScgi::cleanup_thread() {
if (m_scgi != nullptr)
m_scgi.load()->deactivate();
}
rpc::SCgi*
ThreadScgi::scgi() {
return m_scgi;
}
bool
ThreadScgi::set_scgi(rpc::SCgi* scgi) {
rpc::SCgi* expected = nullptr;
if (!m_scgi.compare_exchange_strong(expected, scgi))
return false;
change_rpc_log();
callback(nullptr, [this]() {
if (m_scgi == NULL)
throw torrent::internal_error("Tried to start SCGI but object was not present.");
m_scgi.load()->activate();
});
return true;
}
void
ThreadScgi::set_rpc_log(const std::string& filename) {
callback(nullptr, [this, filename]() {
m_rpc_log_filename = filename;
change_rpc_log();
});
}
void
ThreadScgi::change_rpc_log() {
if (scgi() == NULL)
return;
if (scgi()->log_fd() != -1) {
::close(scgi()->log_fd());
scgi()->set_log_fd(-1);
lt_log_print(torrent::LOG_NOTICE, "Closed RPC log.", 0);
}
if (m_rpc_log_filename.empty())
return;
scgi()->set_log_fd(open(rak::path_expand(m_rpc_log_filename).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644));
if (scgi()->log_fd() == -1) {
lt_log_print(torrent::LOG_NOTICE, "Could not open RPC log file '%s'.", m_rpc_log_filename.c_str());
return;
}
lt_log_print(torrent::LOG_NOTICE, "Logging RPC events to '%s'.", m_rpc_log_filename.c_str());
}
void
ThreadScgi::call_events() {
if ((m_flags & flag_do_shutdown)) {
if ((m_flags & flag_did_shutdown))
throw torrent::internal_error("Already trigged shutdown.");
m_flags |= flag_did_shutdown;
throw torrent::shutdown_exception();
}
process_callbacks();
}
std::chrono::microseconds
ThreadScgi::next_timeout() {
// TODO: This leads to kqueue crash?
// return std::chrono::microseconds(1h);
return std::chrono::microseconds(10min);
}
} // namespace scgi
namespace scgi_thread {
torrent::utils::Thread* thread() { return scgi::ThreadScgiInternal::thread_scgi(); }
std::thread::id thread_id() { return scgi::ThreadScgiInternal::thread_scgi()->thread_id(); }
void callback(void* target, std::function<void ()>&& fn) { scgi::ThreadScgiInternal::thread_scgi()->callback(target, std::move(fn)); }
void cancel_callback(void* target) { scgi::ThreadScgiInternal::thread_scgi()->cancel_callback(target); }
void cancel_callback_and_wait(void* target) { scgi::ThreadScgiInternal::thread_scgi()->cancel_callback_and_wait(target); }
rpc::SCgi* scgi() { return scgi::ThreadScgiInternal::thread_scgi()->scgi(); }
void set_scgi(rpc::SCgi* scgi) { scgi::ThreadScgiInternal::thread_scgi()->set_scgi(scgi); }
void set_rpc_log(const std::string& filename) { scgi::ThreadScgiInternal::thread_scgi()->set_rpc_log(filename); }
} // namespace scgi_thread
+30 -11
View File
@@ -1,5 +1,5 @@
#ifndef RTORRENT_THREAD_WORKER_H
#define RTORRENT_THREAD_WORKER_H
#ifndef RTORRENT_SCGI_THREAD_SCGI_H
#define RTORRENT_SCGI_THREAD_SCGI_H
#include <atomic>
#include <string>
@@ -9,30 +9,49 @@ namespace rpc {
class SCgi;
}
class ThreadWorker : public torrent::utils::Thread {
public:
ThreadWorker() = default;
~ThreadWorker();
namespace scgi {
const char* name() const override { return "rtorrent scgi"; }
class ThreadScgiInternal;
class ThreadScgi : public torrent::utils::Thread {
public:
static void create_thread();
static void destroy_thread();
static ThreadScgi* thread_scgi();
const char* name() const override { return "rtorrent-scgi"; }
void init_thread() override;
void cleanup_thread() override;
rpc::SCgi* scgi() { return m_scgi; }
rpc::SCgi* scgi();
bool set_scgi(rpc::SCgi* scgi);
void set_rpc_log(const std::string& filename);
protected:
friend class ThreadScgiInternal;
ThreadScgi() = default;
static auto internal_thread_scgi() { return m_thread_scgi; }
void call_events() override;
std::chrono::microseconds next_timeout() override;
private:
void task_touch_log();
void change_rpc_log();
void call_events() override;
std::chrono::microseconds next_timeout() override;
static ThreadScgi* m_thread_scgi;
std::atomic<rpc::SCgi*> m_scgi{nullptr};
std::string m_rpc_log_filename;
// std::unique_ptr<ScgiManager> m_manager;
};
#endif // RTORRENT_THREAD_WORKER_H
} // namespace scgi
#endif // RTORRENT_SCGI_THREAD_SCGI_H
+1 -1
View File
@@ -76,7 +76,7 @@ std::chrono::microseconds
ThreadSession::next_timeout() {
// TODO: This leads to kqueue crash?
// return std::chrono::microseconds(1h);
return std::chrono::microseconds(10s);
return std::chrono::microseconds(10min);
}
} // namespace session
-97
View File
@@ -1,97 +0,0 @@
#include "config.h"
#include "thread_worker.h"
#include <fcntl.h>
#include <unistd.h>
#include <cassert>
#include <rak/path.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "control.h"
#include "core/manager.h"
#include "rpc/scgi.h"
#include "rpc/parse_commands.h"
ThreadWorker::~ThreadWorker() = default;
void
ThreadWorker::init_thread() {
m_state = STATE_INITIALIZED;
}
void
ThreadWorker::cleanup_thread() {
if (m_scgi != nullptr)
m_scgi.load()->deactivate();
}
bool
ThreadWorker::set_scgi(rpc::SCgi* scgi) {
rpc::SCgi* expected = nullptr;
if (!m_scgi.compare_exchange_strong(expected, scgi))
return false;
change_rpc_log();
callback(nullptr, [this]() {
if (m_scgi == NULL)
throw torrent::internal_error("Tried to start SCGI but object was not present.");
m_scgi.load()->activate();
});
return true;
}
void
ThreadWorker::set_rpc_log(const std::string& filename) {
callback(nullptr, [this, filename]() {
m_rpc_log_filename = filename;
change_rpc_log();
});
}
void
ThreadWorker::change_rpc_log() {
if (scgi() == NULL)
return;
if (scgi()->log_fd() != -1) {
::close(scgi()->log_fd());
scgi()->set_log_fd(-1);
control->core()->push_log("Closed RPC log.");
}
if (m_rpc_log_filename.empty())
return;
scgi()->set_log_fd(open(rak::path_expand(m_rpc_log_filename).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644));
if (scgi()->log_fd() == -1) {
control->core()->push_log_std("Could not open RPC log file '" + m_rpc_log_filename + "'.");
return;
}
control->core()->push_log_std("Logging RPC events to '" + m_rpc_log_filename + "'.");
}
void
ThreadWorker::call_events() {
if ((m_flags & flag_do_shutdown)) {
if ((m_flags & flag_did_shutdown))
throw torrent::internal_error("Already trigged shutdown.");
m_flags |= flag_did_shutdown;
throw torrent::shutdown_exception();
}
process_callbacks();
}
std::chrono::microseconds
ThreadWorker::next_timeout() {
return std::chrono::microseconds(10min);
}