From b61ebca14afc33bcae27d3aaf4dc1dd955044346 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 2 Nov 2016 01:01:04 -0400 Subject: [PATCH] moved async-load-torrent feature out of disk-io-thread (#1282) moved async-load-torrent feature out of disk-io-thread into a generic worker thread --- include/libtorrent/aux_/session_impl.hpp | 22 ++++++++++++++- include/libtorrent/disk_interface.hpp | 2 -- include/libtorrent/disk_io_job.hpp | 2 -- include/libtorrent/disk_io_thread.hpp | 3 -- src/block_cache.cpp | 1 - src/disk_io_thread.cpp | 33 ---------------------- src/session_impl.cpp | 35 ++++++++++++++---------- test/test_torrent.cpp | 26 ++++++++++++++++++ 8 files changed, 68 insertions(+), 56 deletions(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 754c87c0d..b3a06213c 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -449,7 +449,7 @@ namespace libtorrent std::pair, bool> add_torrent_impl(add_torrent_params& p, error_code& ec); void async_add_torrent(add_torrent_params* params); - void on_async_load_torrent(disk_io_job const* j); + void on_async_load_torrent(add_torrent_params* params, error_code ec); void remove_torrent(torrent_handle const& h, int options) override; void remove_torrent_impl(std::shared_ptr tptr, int options) override; @@ -1058,6 +1058,26 @@ namespace libtorrent std::shared_ptr m_upnp; std::shared_ptr m_lsd; + struct work_thread_t + { + work_thread_t() + : work(new boost::asio::io_service::work(ios)) + , thread([&] { ios.run(); }) + {} + ~work_thread_t() + { + work.reset(); + thread.join(); + } + work_thread_t(work_thread_t const&) = delete; + work_thread_t& operator=(work_thread_t const&) = delete; + + boost::asio::io_service ios; + std::unique_ptr work; + std::thread thread; + }; + std::unique_ptr m_torrent_load_thread; + // mask is a bitmask of which protocols to remap on: // 1: NAT-PMP // 2: UPnP diff --git a/include/libtorrent/disk_interface.hpp b/include/libtorrent/disk_interface.hpp index 88b4089f6..427fd9b7b 100644 --- a/include/libtorrent/disk_interface.hpp +++ b/include/libtorrent/disk_interface.hpp @@ -86,8 +86,6 @@ namespace libtorrent virtual void async_set_file_priority(piece_manager* storage , std::vector const& prio , std::function handler) = 0; - virtual void async_load_torrent(add_torrent_params* params - , std::function handler) = 0; virtual void async_tick_torrent(piece_manager* storage , std::function handler) = 0; diff --git a/include/libtorrent/disk_io_job.hpp b/include/libtorrent/disk_io_job.hpp index 1cc9618b2..6cb87ff5e 100644 --- a/include/libtorrent/disk_io_job.hpp +++ b/include/libtorrent/disk_io_job.hpp @@ -95,7 +95,6 @@ namespace libtorrent , flush_storage , trim_cache , file_priority - , load_torrent , clear_piece , tick_storage , resolve_links @@ -150,7 +149,6 @@ namespace libtorrent char* string; add_torrent_params const* check_resume_data; std::vector* priorities; - torrent_info* torrent_file; int delete_options; } buffer; diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index b93e2c973..dfdc84514 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -324,8 +324,6 @@ namespace libtorrent void async_set_file_priority(piece_manager* storage , std::vector const& prio , std::function handler) override; - void async_load_torrent(add_torrent_params* params - , std::function handler) override; void async_tick_torrent(piece_manager* storage , std::function handler) override; @@ -413,7 +411,6 @@ namespace libtorrent int do_flush_storage(disk_io_job* j, jobqueue_t& completed_jobs); int do_trim_cache(disk_io_job* j, jobqueue_t& completed_jobs); int do_file_priority(disk_io_job* j, jobqueue_t& completed_jobs); - int do_load_torrent(disk_io_job* j, jobqueue_t& completed_jobs); int do_clear_piece(disk_io_job* j, jobqueue_t& completed_jobs); int do_tick(disk_io_job* j, jobqueue_t& completed_jobs); int do_resolve_links(disk_io_job* j, jobqueue_t& completed_jobs); diff --git a/src/block_cache.cpp b/src/block_cache.cpp index 32d40f5bf..d1d9fdd1e 100644 --- a/src/block_cache.cpp +++ b/src/block_cache.cpp @@ -204,7 +204,6 @@ const char* const job_action_name[] = "flush_storage", "trim_cache", "set_file_priority", - "load_torrent", "clear_piece", "tick_storage", "resolve_links" diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 5efcd37ef..b8243ee98 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1032,7 +1032,6 @@ namespace libtorrent &disk_io_thread::do_flush_storage, &disk_io_thread::do_trim_cache, &disk_io_thread::do_file_priority, - &disk_io_thread::do_load_torrent, &disk_io_thread::do_clear_piece, &disk_io_thread::do_tick, }; @@ -1963,16 +1962,6 @@ namespace libtorrent add_fence_job(storage, j); } - void disk_io_thread::async_load_torrent(add_torrent_params* params - , std::function handler) - { - disk_io_job* j = allocate_job(disk_io_job::load_torrent); - j->requester = reinterpret_cast(params); - j->callback = std::move(handler); - - add_job(j); - } - void disk_io_thread::async_tick_torrent(piece_manager* storage , std::function handler) { @@ -2882,28 +2871,6 @@ namespace libtorrent return 0; } - int disk_io_thread::do_load_torrent(disk_io_job* j, jobqueue_t& /* completed_jobs */ ) - { - add_torrent_params* params = reinterpret_cast(j->requester); - - std::string filename = resolve_file_url(params->url); - std::unique_ptr t{new torrent_info(filename, j->error.ec)}; - if (j->error.ec) - { - j->buffer.torrent_file = nullptr; - } - else - { - // do this to trigger parsing of the info-dict here. It's better - // than to have it be done in the network thread. It has enough to - // do as it is. - std::string cert = t->ssl_cert(); - j->buffer.torrent_file = t.release(); - } - - return 0; - } - // this job won't return until all outstanding jobs on this // piece are completed or cancelled and the buffers for it // have been evicted diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 8c91019a8..51115265e 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -4497,8 +4497,18 @@ namespace aux { if (string_begins_no_case("file://", params->url.c_str()) && !params->ti) { - m_disk_thread.async_load_torrent(params - , std::bind(&session_impl::on_async_load_torrent, this, _1)); + if (!m_torrent_load_thread) + m_torrent_load_thread.reset(new work_thread_t()); + + m_torrent_load_thread->ios.post([params, this] + { + std::unique_ptr holder2(params); + error_code ec; + params->ti = std::make_shared(resolve_file_url(params->url), ec); + this->m_io_service.post(std::bind(&session_impl::on_async_load_torrent + , this, params, ec)); + holder2.release(); + }); holder.release(); return; } @@ -4507,22 +4517,19 @@ namespace aux { add_torrent(*params, ec); } - void session_impl::on_async_load_torrent(disk_io_job const* j) + void session_impl::on_async_load_torrent(add_torrent_params* params, error_code ec) { - add_torrent_params* params = reinterpret_cast(j->requester); std::unique_ptr holder(params); - if (j->error.ec) + if (!ec) + { + add_torrent(*params, ec); + params->url.clear(); + } + + if (ec) { m_alerts.emplace_alert(torrent_handle() - , *params, j->error.ec); - } - else - { - params->url.clear(); - params->ti = std::shared_ptr(j->buffer.torrent_file); - - error_code ec; - add_torrent(*params, ec); + , *params, ec); } } diff --git a/test/test_torrent.cpp b/test/test_torrent.cpp index c35a54f9a..771644604 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent.hpp" #include "libtorrent/peer_info.hpp" #include "libtorrent/extensions.hpp" +#include "libtorrent/file.hpp" // for combine_path, current_working_directory #include "settings.hpp" #include #include @@ -411,3 +412,28 @@ TORRENT_TEST(rename_file) TEST_EQUAL(info->files().file_path(0), "tmp1"); } + +TORRENT_TEST(async_load) +{ + settings_pack pack = settings(); + lt::session ses(pack); + + add_torrent_params p; + p.flags &= ~add_torrent_params::flag_paused; + p.flags &= ~add_torrent_params::flag_auto_managed; + std::string dir = parent_path(current_working_directory()); + + p.url = "file://" + combine_path(combine_path(dir, "test_torrents"), "base.torrent"); + p.save_path = "."; + ses.async_add_torrent(p); + + alert const* a = wait_for_alert(ses, add_torrent_alert::alert_type); + TEST_CHECK(a); + if (a == nullptr) return; + auto const* ta = alert_cast(a); + TEST_CHECK(ta); + if (ta == nullptr) return; + TEST_CHECK(!ta->error); + TEST_CHECK(ta->params.ti->name() == "temp"); +} +