fix error handling by exercising code paths where memory allocations fail (#1221)
fix error handling by exercising code paths where memory allocations fail
This commit is contained in:
parent
85fe06659e
commit
524f7b1c27
|
@ -179,6 +179,7 @@ nobase_include_HEADERS = \
|
||||||
aux_/portmap.hpp \
|
aux_/portmap.hpp \
|
||||||
aux_/lsd.hpp \
|
aux_/lsd.hpp \
|
||||||
aux_/has_block.hpp \
|
aux_/has_block.hpp \
|
||||||
|
aux_/scope_end.hpp \
|
||||||
\
|
\
|
||||||
extensions/smart_ban.hpp \
|
extensions/smart_ban.hpp \
|
||||||
extensions/ut_metadata.hpp \
|
extensions/ut_metadata.hpp \
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TORRENT_SCOPE_END_HPP_INCLUDED
|
||||||
|
#define TORRENT_SCOPE_END_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace libtorrent { namespace aux {
|
||||||
|
|
||||||
|
template <typename Fun>
|
||||||
|
struct scope_end_impl
|
||||||
|
{
|
||||||
|
explicit scope_end_impl(Fun f) : m_fun(std::move(f)) {}
|
||||||
|
~scope_end_impl() { if (m_armed) m_fun(); }
|
||||||
|
|
||||||
|
// movable
|
||||||
|
scope_end_impl(scope_end_impl&&) = default;
|
||||||
|
scope_end_impl& operator=(scope_end_impl&&) = default;
|
||||||
|
|
||||||
|
// non-copyable
|
||||||
|
scope_end_impl(scope_end_impl const&) = delete;
|
||||||
|
scope_end_impl& operator=(scope_end_impl const&) = delete;
|
||||||
|
void disarm() { m_armed = false; }
|
||||||
|
private:
|
||||||
|
Fun m_fun;
|
||||||
|
bool m_armed = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Fun>
|
||||||
|
scope_end_impl<Fun> scope_end(Fun f) { return scope_end_impl<Fun>(std::move(f)); }
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -257,6 +257,9 @@ namespace libtorrent
|
||||||
// indicates which LRU list this piece is chained into
|
// indicates which LRU list this piece is chained into
|
||||||
enum cache_state_t
|
enum cache_state_t
|
||||||
{
|
{
|
||||||
|
// not added to the cache
|
||||||
|
none,
|
||||||
|
|
||||||
// this is the LRU list for pieces with dirty blocks
|
// this is the LRU list for pieces with dirty blocks
|
||||||
write_lru,
|
write_lru,
|
||||||
|
|
||||||
|
@ -314,18 +317,18 @@ namespace libtorrent
|
||||||
// ---- 32 bit boundary ---
|
// ---- 32 bit boundary ---
|
||||||
|
|
||||||
// the sum of all refcounts in all blocks
|
// the sum of all refcounts in all blocks
|
||||||
std::uint32_t refcount;
|
std::uint32_t refcount = 0;
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
// the number of times this piece has finished hashing
|
// the number of times this piece has finished hashing
|
||||||
int hash_passes;
|
int hash_passes = 0;
|
||||||
|
|
||||||
// this is a debug facility to keep a log
|
// this is a debug facility to keep a log
|
||||||
// of which operations have been run on this piece
|
// of which operations have been run on this piece
|
||||||
std::vector<piece_log_t> piece_log;
|
std::vector<piece_log_t> piece_log;
|
||||||
|
|
||||||
bool in_storage;
|
bool in_storage = false;
|
||||||
bool in_use;
|
bool in_use = true;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,7 @@ namespace libtorrent
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void check_buffer_level(std::unique_lock<std::mutex>& l);
|
void check_buffer_level(std::unique_lock<std::mutex>& l);
|
||||||
|
void remove_buffer_in_use(char* buf);
|
||||||
|
|
||||||
mutable std::mutex m_pool_mutex;
|
mutable std::mutex m_pool_mutex;
|
||||||
|
|
||||||
|
|
|
@ -618,6 +618,12 @@ namespace libtorrent
|
||||||
std::mutex m_completed_jobs_mutex;
|
std::mutex m_completed_jobs_mutex;
|
||||||
jobqueue_t m_completed_jobs;
|
jobqueue_t m_completed_jobs;
|
||||||
|
|
||||||
|
// this is protected by the completed_jobs_mutex. It's true whenever
|
||||||
|
// there's a call_job_handlers message in-flight to the network thread. We
|
||||||
|
// only ever keep one such message in flight at a time, and coalesce
|
||||||
|
// completion callbacks in m_completed jobs
|
||||||
|
bool m_job_completions_in_flight = false;
|
||||||
|
|
||||||
// these are blocks that have been returned by the main thread
|
// these are blocks that have been returned by the main thread
|
||||||
// but they haven't been freed yet. This is used to batch
|
// but they haven't been freed yet. This is used to batch
|
||||||
// reclaiming of blocks, to only need one std::mutex lock per cycle
|
// reclaiming of blocks, to only need one std::mutex lock per cycle
|
||||||
|
|
|
@ -530,7 +530,8 @@ namespace libtorrent
|
||||||
partfile_read,
|
partfile_read,
|
||||||
partfile_write,
|
partfile_write,
|
||||||
check_resume,
|
check_resume,
|
||||||
hard_link
|
hard_link,
|
||||||
|
exception
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a string literal representing the file operation
|
// Returns a string literal representing the file operation
|
||||||
|
@ -543,7 +544,7 @@ namespace libtorrent
|
||||||
"", "stat", "mkdir", "open", "rename", "remove", "copy"
|
"", "stat", "mkdir", "open", "rename", "remove", "copy"
|
||||||
, "read", "write", "fallocate", "allocate cache piece"
|
, "read", "write", "fallocate", "allocate cache piece"
|
||||||
, "partfile move", "partfile read", "partfile write"
|
, "partfile move", "partfile read", "partfile write"
|
||||||
, "check resume", "hard_link"
|
, "check resume", "hard_link", "exception"
|
||||||
};
|
};
|
||||||
return ops[operation];
|
return ops[operation];
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,23 @@ namespace libtorrent
|
||||||
template<class T>
|
template<class T>
|
||||||
void check_invariant(T const& x)
|
void check_invariant(T const& x)
|
||||||
{
|
{
|
||||||
invariant_access::check_invariant(x);
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
try
|
||||||
|
{
|
||||||
|
invariant_access::check_invariant(x);
|
||||||
|
}
|
||||||
|
catch (std::exception const& err)
|
||||||
|
{
|
||||||
|
std::fprintf(stderr, "invariant_check failed with exception: %s"
|
||||||
|
, err.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::fprintf(stderr, "invariant_check failed with exception");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
invariant_access::check_invariant(x);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct invariant_checker {};
|
struct invariant_checker {};
|
||||||
|
@ -38,14 +54,7 @@ namespace libtorrent
|
||||||
explicit invariant_checker_impl(T const& self_)
|
explicit invariant_checker_impl(T const& self_)
|
||||||
: self(self_)
|
: self(self_)
|
||||||
{
|
{
|
||||||
TORRENT_TRY
|
check_invariant(self);
|
||||||
{
|
|
||||||
check_invariant(self);
|
|
||||||
}
|
|
||||||
TORRENT_CATCH_ALL
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT_FAIL();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
invariant_checker_impl(invariant_checker_impl const& rhs)
|
invariant_checker_impl(invariant_checker_impl const& rhs)
|
||||||
|
@ -53,14 +62,7 @@ namespace libtorrent
|
||||||
|
|
||||||
~invariant_checker_impl()
|
~invariant_checker_impl()
|
||||||
{
|
{
|
||||||
TORRENT_TRY
|
check_invariant(self);
|
||||||
{
|
|
||||||
check_invariant(self);
|
|
||||||
}
|
|
||||||
TORRENT_CATCH_ALL
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT_FAIL();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
T const& self;
|
T const& self;
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (index == -1) return;
|
if (index == -1) return;
|
||||||
TORRENT_ASSERT(index >= 0 && index < int(list.size()));
|
TORRENT_ASSERT(index >= 0 && index < int(list.size()));
|
||||||
int last = int(list.size()) - 1;
|
int const last = int(list.size()) - 1;
|
||||||
if (index < last)
|
if (index < last)
|
||||||
{
|
{
|
||||||
list[last]->m_links[link_index].index = index;
|
list[last]->m_links[link_index].index = index;
|
||||||
|
@ -67,8 +67,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (index >= 0) return;
|
if (index >= 0) return;
|
||||||
TORRENT_ASSERT(index == -1);
|
TORRENT_ASSERT(index == -1);
|
||||||
index = int(list.size());
|
|
||||||
list.push_back(self);
|
list.push_back(self);
|
||||||
|
index = int(list.size()) - 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,6 +299,21 @@ namespace libtorrent
|
||||||
// starts the announce timer
|
// starts the announce timer
|
||||||
void start(add_torrent_params const& p);
|
void start(add_torrent_params const& p);
|
||||||
|
|
||||||
|
void added()
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_added == false);
|
||||||
|
m_added = true;
|
||||||
|
update_gauge();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removed()
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_added == true);
|
||||||
|
m_added = false;
|
||||||
|
// make sure we decrement the gauge counter for this torrent
|
||||||
|
update_gauge();
|
||||||
|
}
|
||||||
|
|
||||||
void start_download_url();
|
void start_download_url();
|
||||||
|
|
||||||
// returns which stats gauge this torrent currently
|
// returns which stats gauge this torrent currently
|
||||||
|
@ -1083,6 +1098,8 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
void add_suggest_piece(int index);
|
void add_suggest_piece(int index);
|
||||||
|
|
||||||
|
enum { no_gauge_state = 0xf };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ip_filter_updated();
|
void ip_filter_updated();
|
||||||
|
@ -1403,6 +1420,10 @@ namespace libtorrent
|
||||||
// is is disabled while paused and checking files
|
// is is disabled while paused and checking files
|
||||||
bool m_announcing:1;
|
bool m_announcing:1;
|
||||||
|
|
||||||
|
// this is true when the torrent has been added to the session. Before
|
||||||
|
// then, it isn't included in the counters (session_stats)
|
||||||
|
bool m_added:1;
|
||||||
|
|
||||||
// this is > 0 while the tracker deadline timer
|
// this is > 0 while the tracker deadline timer
|
||||||
// is in use. i.e. one or more trackers are waiting
|
// is in use. i.e. one or more trackers are waiting
|
||||||
// for a reannounce
|
// for a reannounce
|
||||||
|
@ -1580,7 +1601,6 @@ namespace libtorrent
|
||||||
// slots.
|
// slots.
|
||||||
bool m_auto_managed:1;
|
bool m_auto_managed:1;
|
||||||
|
|
||||||
enum { no_gauge_state = 0xf };
|
|
||||||
// the current stats gauge this torrent counts against
|
// the current stats gauge this torrent counts against
|
||||||
std::uint32_t m_current_gauge_state:4;
|
std::uint32_t m_current_gauge_state:4;
|
||||||
|
|
||||||
|
|
|
@ -258,7 +258,7 @@ namespace libtorrent
|
||||||
bool cancelled() const { return m_abort; }
|
bool cancelled() const { return m_abort; }
|
||||||
|
|
||||||
virtual void on_timeout(error_code const& ec) = 0;
|
virtual void on_timeout(error_code const& ec) = 0;
|
||||||
virtual ~timeout_handler() {}
|
virtual ~timeout_handler();
|
||||||
|
|
||||||
io_service& get_io_service() { return m_timeout.get_io_service(); }
|
io_service& get_io_service() { return m_timeout.get_io_service(); }
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ namespace libtorrent
|
||||||
|
|
||||||
void timeout_callback(error_code const&);
|
void timeout_callback(error_code const&);
|
||||||
|
|
||||||
int m_completion_timeout;
|
int m_completion_timeout = 0;
|
||||||
|
|
||||||
// used for timeouts
|
// used for timeouts
|
||||||
// this is set when the request has been sent
|
// this is set when the request has been sent
|
||||||
|
@ -278,9 +278,12 @@ namespace libtorrent
|
||||||
// the asio async operation
|
// the asio async operation
|
||||||
deadline_timer m_timeout;
|
deadline_timer m_timeout;
|
||||||
|
|
||||||
int m_read_timeout;
|
int m_read_timeout = 0;
|
||||||
|
|
||||||
bool m_abort;
|
bool m_abort = false;
|
||||||
|
#if TORRENT_USE_ASSERTS
|
||||||
|
int m_outstanding_timer_wait = 0;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: 2 this class probably doesn't need to have virtual functions.
|
// TODO: 2 this class probably doesn't need to have virtual functions.
|
||||||
|
@ -402,11 +405,10 @@ namespace libtorrent
|
||||||
resolver_interface& m_host_resolver;
|
resolver_interface& m_host_resolver;
|
||||||
aux::session_settings const& m_settings;
|
aux::session_settings const& m_settings;
|
||||||
counters& m_stats_counters;
|
counters& m_stats_counters;
|
||||||
|
bool m_abort = false;
|
||||||
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
|
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
|
||||||
aux::session_logger& m_ses;
|
aux::session_logger& m_ses;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool m_abort;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,3 +52,6 @@ alias libtorrent-sims :
|
||||||
[ run test_save_resume.cpp ]
|
[ run test_save_resume.cpp ]
|
||||||
;
|
;
|
||||||
|
|
||||||
|
run test_error_handling.cpp ;
|
||||||
|
explicit test_error_handling ;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2016, Arvid Norberg
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the author nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "test.hpp"
|
||||||
|
#include "create_torrent.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
#include "libtorrent/session.hpp"
|
||||||
|
#include "libtorrent/session_stats.hpp"
|
||||||
|
#include "libtorrent/settings_pack.hpp"
|
||||||
|
#include "libtorrent/ip_filter.hpp"
|
||||||
|
#include "libtorrent/alert_types.hpp"
|
||||||
|
#include "libtorrent/aux_/proxy_settings.hpp"
|
||||||
|
#include "libtorrent/settings_pack.hpp"
|
||||||
|
#include "simulator/simulator.hpp"
|
||||||
|
#include "simulator/socks_server.hpp"
|
||||||
|
#include "simulator/utils.hpp"
|
||||||
|
#include "setup_swarm.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
#include "setup_transfer.hpp" // for addr()
|
||||||
|
|
||||||
|
using namespace sim;
|
||||||
|
|
||||||
|
namespace lt = libtorrent;
|
||||||
|
|
||||||
|
std::string make_ep_string(char const* address, bool const is_v6
|
||||||
|
, char const* port)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
if (is_v6) ret += '[';
|
||||||
|
ret += address;
|
||||||
|
if (is_v6) ret += ']';
|
||||||
|
ret += ':';
|
||||||
|
ret += port;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandleAlerts, typename Test>
|
||||||
|
void run_test(HandleAlerts const& on_alert, Test const& test)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
using asio::ip::address;
|
||||||
|
address const peer0 = addr("50.0.0.1");
|
||||||
|
address const peer1 = addr("50.0.0.2");
|
||||||
|
|
||||||
|
// setup the simulation
|
||||||
|
sim::default_config network_cfg;
|
||||||
|
sim::simulation sim{network_cfg};
|
||||||
|
sim::asio::io_service ios0 { sim, peer0 };
|
||||||
|
sim::asio::io_service ios1 { sim, peer1 };
|
||||||
|
|
||||||
|
lt::session_proxy zombie[2];
|
||||||
|
|
||||||
|
// setup settings pack to use for the session (customization point)
|
||||||
|
lt::settings_pack pack = settings();
|
||||||
|
|
||||||
|
// disable utp by default
|
||||||
|
pack.set_bool(settings_pack::enable_outgoing_utp, false);
|
||||||
|
pack.set_bool(settings_pack::enable_incoming_utp, false);
|
||||||
|
|
||||||
|
// disable encryption by default
|
||||||
|
pack.set_bool(settings_pack::prefer_rc4, false);
|
||||||
|
pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled);
|
||||||
|
pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled);
|
||||||
|
pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_plaintext);
|
||||||
|
|
||||||
|
pack.set_str(settings_pack::listen_interfaces, peer0.to_string() + ":6881");
|
||||||
|
|
||||||
|
// create session
|
||||||
|
std::shared_ptr<lt::session> ses[2];
|
||||||
|
ses[0] = std::make_shared<lt::session>(pack, ios0);
|
||||||
|
|
||||||
|
pack.set_str(settings_pack::listen_interfaces, peer1.to_string() + ":6881");
|
||||||
|
ses[1] = std::make_shared<lt::session>(pack, ios1);
|
||||||
|
|
||||||
|
// only monitor alerts for session 0 (the downloader)
|
||||||
|
print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
|
||||||
|
if (auto ta = alert_cast<lt::torrent_added_alert>(a))
|
||||||
|
{
|
||||||
|
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
|
||||||
|
}
|
||||||
|
on_alert(ses, a);
|
||||||
|
});
|
||||||
|
|
||||||
|
print_alerts(*ses[1]);
|
||||||
|
|
||||||
|
// the first peer is a downloader, the second peer is a seed
|
||||||
|
lt::add_torrent_params params = create_torrent(1);
|
||||||
|
params.flags &= ~lt::add_torrent_params::flag_auto_managed;
|
||||||
|
params.flags &= ~lt::add_torrent_params::flag_paused;
|
||||||
|
|
||||||
|
params.save_path = save_path(0);
|
||||||
|
ses[0]->async_add_torrent(params);
|
||||||
|
|
||||||
|
params.save_path = save_path(1);
|
||||||
|
ses[1]->async_add_torrent(params);
|
||||||
|
|
||||||
|
sim::timer t(sim, lt::seconds(60), [&](boost::system::error_code const& ec)
|
||||||
|
{
|
||||||
|
test(ses);
|
||||||
|
|
||||||
|
// shut down
|
||||||
|
int idx = 0;
|
||||||
|
for (auto& s : ses)
|
||||||
|
{
|
||||||
|
zombie[idx++] = s->abort();
|
||||||
|
s.reset();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sim.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
int g_alloc_counter = 1000000;
|
||||||
|
|
||||||
|
void* operator new(std::size_t sz)
|
||||||
|
{
|
||||||
|
if (--g_alloc_counter == 0)
|
||||||
|
{
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
return std::malloc(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator delete(void* ptr) noexcept
|
||||||
|
{
|
||||||
|
std::free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(no_proxy_tcp)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3000; ++i)
|
||||||
|
{
|
||||||
|
std::printf("\n\n === ROUND %d ===\n\n", i);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
g_alloc_counter = 100 + i;
|
||||||
|
using namespace libtorrent;
|
||||||
|
run_test(
|
||||||
|
[](lt::session&, lt::alert const*) {},
|
||||||
|
[](std::shared_ptr<lt::session> ses[2]) {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (std::bad_alloc const&)
|
||||||
|
{
|
||||||
|
// this is kind of expected
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
TEST_ERROR("session constructor terminated with unexpected exception. round: "
|
||||||
|
+ std::to_string(i));
|
||||||
|
}
|
||||||
|
// if we didn't fail any allocations this run, there's no need to
|
||||||
|
// continue, we won't exercise any new code paths
|
||||||
|
if (g_alloc_counter > 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -126,15 +126,22 @@ void print_alerts(lt::session& ses
|
||||||
ses.set_alert_notify([&ses,start_time,on_alert] {
|
ses.set_alert_notify([&ses,start_time,on_alert] {
|
||||||
ses.get_io_service().post([&ses,start_time,on_alert] {
|
ses.get_io_service().post([&ses,start_time,on_alert] {
|
||||||
|
|
||||||
std::vector<lt::alert*> alerts;
|
try {
|
||||||
ses.pop_alerts(&alerts);
|
std::vector<lt::alert*> alerts;
|
||||||
|
ses.pop_alerts(&alerts);
|
||||||
|
|
||||||
for (lt::alert const* a : alerts)
|
for (lt::alert const* a : alerts)
|
||||||
{
|
{
|
||||||
std::printf("%-3d [0] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
|
std::printf("%-3d [0] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
|
||||||
- start_time).count()), a->message().c_str());
|
- start_time).count()), a->message().c_str());
|
||||||
// call the user handler
|
// call the user handler
|
||||||
on_alert(ses, a);
|
on_alert(ses, a);
|
||||||
|
}
|
||||||
|
} catch (std::exception const& e) {
|
||||||
|
std::printf("print alerts: ERROR failed with exception: %s"
|
||||||
|
, e.what());
|
||||||
|
} catch (...) {
|
||||||
|
std::printf("print alerts: ERROR failed with (unknown) exception");
|
||||||
}
|
}
|
||||||
} ); } );
|
} ); } );
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,17 +320,11 @@ cached_piece_entry::cached_piece_entry()
|
||||||
, hashing_done(0)
|
, hashing_done(0)
|
||||||
, marked_for_deletion(false)
|
, marked_for_deletion(false)
|
||||||
, need_readback(false)
|
, need_readback(false)
|
||||||
, cache_state(read_lru1)
|
, cache_state(none)
|
||||||
, piece_refcount(0)
|
, piece_refcount(0)
|
||||||
, outstanding_flush(0)
|
, outstanding_flush(0)
|
||||||
, outstanding_read(0)
|
, outstanding_read(0)
|
||||||
, pinned(0)
|
, pinned(0)
|
||||||
, refcount(0)
|
|
||||||
#if TORRENT_USE_ASSERTS
|
|
||||||
, hash_passes(0)
|
|
||||||
, in_storage(false)
|
|
||||||
, in_use(true)
|
|
||||||
#endif
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
cached_piece_entry::~cached_piece_entry()
|
cached_piece_entry::~cached_piece_entry()
|
||||||
|
@ -339,13 +333,16 @@ cached_piece_entry::~cached_piece_entry()
|
||||||
TORRENT_ASSERT(jobs.size() == 0);
|
TORRENT_ASSERT(jobs.size() == 0);
|
||||||
TORRENT_ASSERT(read_jobs.size() == 0);
|
TORRENT_ASSERT(read_jobs.size() == 0);
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
for (int i = 0; i < blocks_in_piece; ++i)
|
if (blocks)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(blocks[i].buf == nullptr);
|
for (int i = 0; i < blocks_in_piece; ++i)
|
||||||
TORRENT_ASSERT(!blocks[i].pending);
|
{
|
||||||
TORRENT_ASSERT(blocks[i].refcount == 0);
|
TORRENT_ASSERT(blocks[i].buf == nullptr);
|
||||||
TORRENT_ASSERT(blocks[i].hashing_count == 0);
|
TORRENT_ASSERT(!blocks[i].pending);
|
||||||
TORRENT_ASSERT(blocks[i].flushing_count == 0);
|
TORRENT_ASSERT(blocks[i].refcount == 0);
|
||||||
|
TORRENT_ASSERT(blocks[i].hashing_count == 0);
|
||||||
|
TORRENT_ASSERT(blocks[i].flushing_count == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
in_use = false;
|
in_use = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -646,14 +643,14 @@ cached_piece_entry* block_cache::allocate_piece(disk_io_job const* j, int cache_
|
||||||
pe.storage = j->storage;
|
pe.storage = j->storage;
|
||||||
pe.expire = aux::time_now();
|
pe.expire = aux::time_now();
|
||||||
pe.blocks_in_piece = blocks_in_piece;
|
pe.blocks_in_piece = blocks_in_piece;
|
||||||
|
|
||||||
pe.blocks.reset(new (std::nothrow) cached_block_entry[blocks_in_piece]);
|
pe.blocks.reset(new (std::nothrow) cached_block_entry[blocks_in_piece]);
|
||||||
pe.cache_state = cache_state;
|
|
||||||
pe.last_requester = j->requester;
|
|
||||||
TORRENT_PIECE_ASSERT(pe.blocks, &pe);
|
|
||||||
if (!pe.blocks) return nullptr;
|
if (!pe.blocks) return nullptr;
|
||||||
|
pe.last_requester = j->requester;
|
||||||
p = const_cast<cached_piece_entry*>(&*m_pieces.insert(pe).first);
|
p = const_cast<cached_piece_entry*>(&*m_pieces.insert(pe).first);
|
||||||
|
|
||||||
j->storage->add_piece(p);
|
j->storage->add_piece(p);
|
||||||
|
p->cache_state = cache_state;
|
||||||
|
|
||||||
TORRENT_PIECE_ASSERT(p->cache_state < cached_piece_entry::num_lrus, p);
|
TORRENT_PIECE_ASSERT(p->cache_state < cached_piece_entry::num_lrus, p);
|
||||||
linked_list<cached_piece_entry>* lru_list = &m_lru[p->cache_state];
|
linked_list<cached_piece_entry>* lru_list = &m_lru[p->cache_state];
|
||||||
|
@ -1667,7 +1664,7 @@ void block_cache::check_invariant() const
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_set<char*> buffers;
|
std::unordered_set<char*> buffers;
|
||||||
for (auto const& p :m_pieces)
|
for (auto const& p : m_pieces)
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_ASSERT(p.blocks, &p);
|
TORRENT_PIECE_ASSERT(p.blocks, &p);
|
||||||
|
|
||||||
|
@ -1677,7 +1674,7 @@ void block_cache::check_invariant() const
|
||||||
int num_pending = 0;
|
int num_pending = 0;
|
||||||
int num_refcount = 0;
|
int num_refcount = 0;
|
||||||
|
|
||||||
bool in_storage = p.storage->has_piece(&p);
|
bool const in_storage = p.storage->has_piece(&p);
|
||||||
switch (p.cache_state)
|
switch (p.cache_state)
|
||||||
{
|
{
|
||||||
case cached_piece_entry::write_lru:
|
case cached_piece_entry::write_lru:
|
||||||
|
|
|
@ -232,7 +232,12 @@ namespace libtorrent
|
||||||
// we need to roll back and free all the buffers
|
// we need to roll back and free all the buffers
|
||||||
// we've already allocated
|
// we've already allocated
|
||||||
for (int j = 0; j < i; ++j)
|
for (int j = 0; j < i; ++j)
|
||||||
free_buffer_impl(static_cast<char*>(iov[j].iov_base), l);
|
{
|
||||||
|
char* buf = static_cast<char*>(iov[j].iov_base);
|
||||||
|
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
||||||
|
free_buffer_impl(buf, l);
|
||||||
|
remove_buffer_in_use(buf);
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +249,12 @@ namespace libtorrent
|
||||||
// TODO: perhaps we should sort the buffers here?
|
// TODO: perhaps we should sort the buffers here?
|
||||||
std::unique_lock<std::mutex> l(m_pool_mutex);
|
std::unique_lock<std::mutex> l(m_pool_mutex);
|
||||||
for (int i = 0; i < iov_len; ++i)
|
for (int i = 0; i < iov_len; ++i)
|
||||||
free_buffer_impl(static_cast<char*>(iov[i].iov_base), l);
|
{
|
||||||
|
char* buf = static_cast<char*>(iov[i].iov_base);
|
||||||
|
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
||||||
|
free_buffer_impl(buf, l);
|
||||||
|
remove_buffer_in_use(buf);
|
||||||
|
}
|
||||||
check_buffer_level(l);
|
check_buffer_level(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,12 +314,21 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++m_in_use;
|
||||||
|
|
||||||
#if TORRENT_USE_INVARIANT_CHECKS
|
#if TORRENT_USE_INVARIANT_CHECKS
|
||||||
TORRENT_ASSERT(m_buffers_in_use.count(ret) == 0);
|
try
|
||||||
m_buffers_in_use.insert(ret);
|
{
|
||||||
|
TORRENT_ASSERT(m_buffers_in_use.count(ret) == 0);
|
||||||
|
m_buffers_in_use.insert(ret);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
free_buffer_impl(ret, l);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
++m_in_use;
|
|
||||||
if (m_in_use >= m_low_watermark + (m_max_use - m_low_watermark)
|
if (m_in_use >= m_low_watermark + (m_max_use - m_low_watermark)
|
||||||
/ 2 && !m_exceeded_max_size)
|
/ 2 && !m_exceeded_max_size)
|
||||||
{
|
{
|
||||||
|
@ -331,8 +350,9 @@ namespace libtorrent
|
||||||
for (; bufvec != end; ++bufvec)
|
for (; bufvec != end; ++bufvec)
|
||||||
{
|
{
|
||||||
char* buf = *bufvec;
|
char* buf = *bufvec;
|
||||||
TORRENT_ASSERT(buf);
|
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
||||||
free_buffer_impl(buf, l);
|
free_buffer_impl(buf, l);
|
||||||
|
remove_buffer_in_use(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_buffer_level(l);
|
check_buffer_level(l);
|
||||||
|
@ -341,7 +361,9 @@ namespace libtorrent
|
||||||
void disk_buffer_pool::free_buffer(char* buf)
|
void disk_buffer_pool::free_buffer(char* buf)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_pool_mutex);
|
std::unique_lock<std::mutex> l(m_pool_mutex);
|
||||||
|
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
||||||
free_buffer_impl(buf, l);
|
free_buffer_impl(buf, l);
|
||||||
|
remove_buffer_in_use(buf);
|
||||||
check_buffer_level(l);
|
check_buffer_level(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,12 +536,21 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disk_buffer_pool::remove_buffer_in_use(char* buf)
|
||||||
|
{
|
||||||
|
TORRENT_UNUSED(buf);
|
||||||
|
#if TORRENT_USE_INVARIANT_CHECKS
|
||||||
|
std::set<char*>::iterator i = m_buffers_in_use.find(buf);
|
||||||
|
TORRENT_ASSERT(i != m_buffers_in_use.end());
|
||||||
|
m_buffers_in_use.erase(i);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void disk_buffer_pool::free_buffer_impl(char* buf, std::unique_lock<std::mutex>& l)
|
void disk_buffer_pool::free_buffer_impl(char* buf, std::unique_lock<std::mutex>& l)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(buf);
|
TORRENT_ASSERT(buf);
|
||||||
TORRENT_ASSERT(m_magic == 0x1337);
|
TORRENT_ASSERT(m_magic == 0x1337);
|
||||||
TORRENT_ASSERT(m_settings_set);
|
TORRENT_ASSERT(m_settings_set);
|
||||||
TORRENT_ASSERT(is_disk_buffer(buf, l));
|
|
||||||
TORRENT_ASSERT(l.owns_lock());
|
TORRENT_ASSERT(l.owns_lock());
|
||||||
TORRENT_UNUSED(l);
|
TORRENT_UNUSED(l);
|
||||||
|
|
||||||
|
@ -558,12 +589,6 @@ namespace libtorrent
|
||||||
#endif // TORRENT_DISABLE_POOL_ALLOCATOR
|
#endif // TORRENT_DISABLE_POOL_ALLOCATOR
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_INVARIANT_CHECKS
|
|
||||||
std::set<char*>::iterator i = m_buffers_in_use.find(buf);
|
|
||||||
TORRENT_ASSERT(i != m_buffers_in_use.end());
|
|
||||||
m_buffers_in_use.erase(i);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
--m_in_use;
|
--m_in_use;
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
|
||||||
|
|
|
@ -125,6 +125,53 @@ namespace libtorrent
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct piece_refcount_holder
|
||||||
|
{
|
||||||
|
explicit piece_refcount_holder(cached_piece_entry* p) : m_pe(p)
|
||||||
|
{ ++m_pe->piece_refcount; }
|
||||||
|
~piece_refcount_holder()
|
||||||
|
{
|
||||||
|
if (!m_executed)
|
||||||
|
{
|
||||||
|
TORRENT_PIECE_ASSERT(m_pe->piece_refcount > 0, m_pe);
|
||||||
|
--m_pe->piece_refcount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
piece_refcount_holder(piece_refcount_holder const&) = delete;
|
||||||
|
piece_refcount_holder& operator=(piece_refcount_holder const&) = delete;
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(!m_executed);
|
||||||
|
m_executed = true;
|
||||||
|
TORRENT_PIECE_ASSERT(m_pe->piece_refcount > 0, m_pe);
|
||||||
|
--m_pe->piece_refcount;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
cached_piece_entry* m_pe;
|
||||||
|
bool m_executed = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Lock>
|
||||||
|
struct scoped_unlocker_impl
|
||||||
|
{
|
||||||
|
explicit scoped_unlocker_impl(Lock& l) : m_lock(&l) { m_lock->unlock(); }
|
||||||
|
~scoped_unlocker_impl() { if (m_lock) m_lock->lock(); }
|
||||||
|
scoped_unlocker_impl(scoped_unlocker_impl&& rhs) : m_lock(rhs.m_lock)
|
||||||
|
{ rhs.m_lock = nullptr; }
|
||||||
|
scoped_unlocker_impl& operator=(scoped_unlocker_impl&& rhs)
|
||||||
|
{
|
||||||
|
if (m_lock) m_lock->lock();
|
||||||
|
m_lock = rhs.m_lock;
|
||||||
|
rhs.m_lock = nullptr;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Lock* m_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Lock>
|
||||||
|
scoped_unlocker_impl<Lock> scoped_unlock(Lock& l)
|
||||||
|
{ return scoped_unlocker_impl<Lock>(l); }
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
// ------- disk_io_thread ------
|
// ------- disk_io_thread ------
|
||||||
|
@ -451,12 +498,13 @@ namespace libtorrent
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
l.unlock();
|
|
||||||
|
|
||||||
storage_error error;
|
storage_error error;
|
||||||
flush_iovec(first_piece, iov, flushing, iov_len, error);
|
{
|
||||||
|
// unlock while we're performing the actual disk I/O
|
||||||
l.lock();
|
// then lock again
|
||||||
|
auto unlock = scoped_unlock(l);
|
||||||
|
flush_iovec(first_piece, iov, flushing, iov_len, error);
|
||||||
|
}
|
||||||
|
|
||||||
block_start = 0;
|
block_start = 0;
|
||||||
for (int i = 0; i < cont_pieces; ++i)
|
for (int i = 0; i < cont_pieces; ++i)
|
||||||
|
@ -703,17 +751,15 @@ namespace libtorrent
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
pe->piece_log.push_back(piece_log_t(piece_log_t::flush_range, -1));
|
pe->piece_log.push_back(piece_log_t(piece_log_t::flush_range, -1));
|
||||||
#endif
|
#endif
|
||||||
++pe->piece_refcount;
|
|
||||||
|
|
||||||
l.unlock();
|
|
||||||
|
|
||||||
storage_error error;
|
storage_error error;
|
||||||
flush_iovec(pe, iov, flushing, iov_len, error);
|
{
|
||||||
|
piece_refcount_holder refcount_holder(pe);
|
||||||
|
auto unlocker = scoped_unlock(l);
|
||||||
|
|
||||||
l.lock();
|
flush_iovec(pe, iov, flushing, iov_len, error);
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_PIECE_ASSERT(pe->piece_refcount > 0, pe);
|
|
||||||
--pe->piece_refcount;
|
|
||||||
iovec_flushed(pe, flushing, iov_len, 0, error, completed_jobs);
|
iovec_flushed(pe, flushing, iov_len, 0, error, completed_jobs);
|
||||||
|
|
||||||
// if the cache is under high pressure, we need to evict
|
// if the cache is under high pressure, we need to evict
|
||||||
|
@ -1068,7 +1114,30 @@ namespace libtorrent
|
||||||
m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, 1);
|
m_stats_counters.inc_stats_counter(counters::num_running_disk_jobs, 1);
|
||||||
|
|
||||||
// call disk function
|
// call disk function
|
||||||
int ret = (this->*(job_functions[j->action]))(j, completed_jobs);
|
// TODO: in the future, propagate exceptions back to the handlers
|
||||||
|
int ret = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ret = (this->*(job_functions[j->action]))(j, completed_jobs);
|
||||||
|
}
|
||||||
|
catch (boost::system::system_error const& err)
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
j->error.ec = err.code();
|
||||||
|
j->error.operation = storage_error::exception;
|
||||||
|
}
|
||||||
|
catch (std::bad_alloc const&)
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
j->error.ec = errors::no_memory;
|
||||||
|
j->error.operation = storage_error::exception;
|
||||||
|
}
|
||||||
|
catch (std::exception const&)
|
||||||
|
{
|
||||||
|
ret = -1;
|
||||||
|
j->error.ec = boost::asio::error::fault;
|
||||||
|
j->error.operation = storage_error::exception;
|
||||||
|
}
|
||||||
|
|
||||||
// note that -2 errors are OK
|
// note that -2 errors are OK
|
||||||
TORRENT_ASSERT(ret != -1 || (j->error.ec && j->error.operation != 0));
|
TORRENT_ASSERT(ret != -1 || (j->error.ec && j->error.operation != 0));
|
||||||
|
@ -2158,9 +2227,10 @@ namespace libtorrent
|
||||||
m_disk_cache.cache_hit(pe, j->requester, (j->flags & disk_io_job::volatile_read) != 0);
|
m_disk_cache.cache_hit(pe, j->requester, (j->flags & disk_io_job::volatile_read) != 0);
|
||||||
|
|
||||||
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1 || pe->cache_state == cached_piece_entry::read_lru2, pe);
|
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1 || pe->cache_state == cached_piece_entry::read_lru2, pe);
|
||||||
++pe->piece_refcount;
|
{
|
||||||
kick_hasher(pe, l);
|
piece_refcount_holder h(pe);
|
||||||
--pe->piece_refcount;
|
kick_hasher(pe, l);
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1 || pe->cache_state == cached_piece_entry::read_lru2, pe);
|
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1 || pe->cache_state == cached_piece_entry::read_lru2, pe);
|
||||||
|
|
||||||
|
@ -2215,7 +2285,8 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
|
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
|
||||||
|| pe->cache_state == cached_piece_entry::read_lru2, pe);
|
|| pe->cache_state == cached_piece_entry::read_lru2, pe);
|
||||||
++pe->piece_refcount;
|
|
||||||
|
piece_refcount_holder refcount_holder(pe);
|
||||||
|
|
||||||
if (pe->hash == nullptr)
|
if (pe->hash == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -2277,14 +2348,12 @@ namespace libtorrent
|
||||||
if (iov.iov_base == nullptr)
|
if (iov.iov_base == nullptr)
|
||||||
{
|
{
|
||||||
l.lock();
|
l.lock();
|
||||||
// TODO: introduce a holder class that automatically increments
|
|
||||||
// and decrements the piece_refcount
|
|
||||||
|
|
||||||
// decrement the refcounts of the blocks we just hashed
|
// decrement the refcounts of the blocks we just hashed
|
||||||
for (int k = 0; k < num_locked_blocks; ++k)
|
for (int k = 0; k < num_locked_blocks; ++k)
|
||||||
m_disk_cache.dec_block_refcount(pe, locked_blocks[k], block_cache::ref_hashing);
|
m_disk_cache.dec_block_refcount(pe, locked_blocks[k], block_cache::ref_hashing);
|
||||||
|
|
||||||
--pe->piece_refcount;
|
refcount_holder.release();
|
||||||
pe->hashing = false;
|
pe->hashing = false;
|
||||||
delete pe->hash;
|
delete pe->hash;
|
||||||
pe->hash = nullptr;
|
pe->hash = nullptr;
|
||||||
|
@ -2352,7 +2421,7 @@ namespace libtorrent
|
||||||
for (int i = 0; i < num_locked_blocks; ++i)
|
for (int i = 0; i < num_locked_blocks; ++i)
|
||||||
m_disk_cache.dec_block_refcount(pe, locked_blocks[i], block_cache::ref_hashing);
|
m_disk_cache.dec_block_refcount(pe, locked_blocks[i], block_cache::ref_hashing);
|
||||||
|
|
||||||
--pe->piece_refcount;
|
refcount_holder.release();
|
||||||
|
|
||||||
pe->hashing = 0;
|
pe->hashing = 0;
|
||||||
|
|
||||||
|
@ -2502,7 +2571,8 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
|
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
|
||||||
|| pe->cache_state == cached_piece_entry::read_lru2, pe);
|
|| pe->cache_state == cached_piece_entry::read_lru2, pe);
|
||||||
++pe->piece_refcount;
|
|
||||||
|
piece_refcount_holder refcount_holder(pe);
|
||||||
|
|
||||||
int block_size = m_disk_cache.block_size();
|
int block_size = m_disk_cache.block_size();
|
||||||
int piece_size = j->storage->files()->piece_size(j->piece);
|
int piece_size = j->storage->files()->piece_size(j->piece);
|
||||||
|
@ -2526,8 +2596,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (iov.iov_base == nullptr)
|
if (iov.iov_base == nullptr)
|
||||||
{
|
{
|
||||||
//#error introduce a holder class that automatically increments and decrements the piece_refcount
|
refcount_holder.release();
|
||||||
--pe->piece_refcount;
|
|
||||||
m_disk_cache.maybe_free_piece(pe);
|
m_disk_cache.maybe_free_piece(pe);
|
||||||
j->error.ec = errors::no_memory;
|
j->error.ec = errors::no_memory;
|
||||||
j->error.operation = storage_error::alloc_cache_piece;
|
j->error.operation = storage_error::alloc_cache_piece;
|
||||||
|
@ -2565,7 +2634,7 @@ namespace libtorrent
|
||||||
m_disk_cache.insert_blocks(pe, i, &iov, 1, j);
|
m_disk_cache.insert_blocks(pe, i, &iov, 1, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
--pe->piece_refcount;
|
refcount_holder.release();
|
||||||
m_disk_cache.maybe_free_piece(pe);
|
m_disk_cache.maybe_free_piece(pe);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2757,7 +2826,8 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
|
TORRENT_PIECE_ASSERT(pe->cache_state <= cached_piece_entry::read_lru1
|
||||||
|| pe->cache_state == cached_piece_entry::read_lru2, pe);
|
|| pe->cache_state == cached_piece_entry::read_lru2, pe);
|
||||||
++pe->piece_refcount;
|
|
||||||
|
piece_refcount_holder refcount_holder(pe);
|
||||||
|
|
||||||
if (!pe->hashing_done)
|
if (!pe->hashing_done)
|
||||||
{
|
{
|
||||||
|
@ -2782,7 +2852,7 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(l.owns_lock());
|
TORRENT_ASSERT(l.owns_lock());
|
||||||
|
|
||||||
--pe->piece_refcount;
|
refcount_holder.release();
|
||||||
|
|
||||||
m_disk_cache.maybe_free_piece(pe);
|
m_disk_cache.maybe_free_piece(pe);
|
||||||
|
|
||||||
|
@ -3318,10 +3388,11 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_DISK_THREAD
|
if (ret)
|
||||||
if (ret) DLOG("unblocked %d jobs (%d left)\n", ret
|
{
|
||||||
, int(m_stats_counters[counters::blocked_disk_jobs]) - ret);
|
DLOG("unblocked %d jobs (%d left)\n", ret
|
||||||
#endif
|
, int(m_stats_counters[counters::blocked_disk_jobs]) - ret);
|
||||||
|
}
|
||||||
|
|
||||||
m_stats_counters.inc_stats_counter(counters::blocked_disk_jobs, -ret);
|
m_stats_counters.inc_stats_counter(counters::blocked_disk_jobs, -ret);
|
||||||
TORRENT_ASSERT(int(m_stats_counters[counters::blocked_disk_jobs]) >= 0);
|
TORRENT_ASSERT(int(m_stats_counters[counters::blocked_disk_jobs]) >= 0);
|
||||||
|
@ -3414,9 +3485,10 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
l_.unlock();
|
l_.unlock();
|
||||||
|
|
||||||
std::unique_lock<std::mutex> l(m_job_mutex);
|
{
|
||||||
m_generic_io_jobs.m_queued_jobs.append(other_jobs);
|
std::lock_guard<std::mutex> l(m_job_mutex);
|
||||||
l.unlock();
|
m_generic_io_jobs.m_queued_jobs.append(other_jobs);
|
||||||
|
}
|
||||||
|
|
||||||
while (flush_jobs.size() > 0)
|
while (flush_jobs.size() > 0)
|
||||||
{
|
{
|
||||||
|
@ -3424,25 +3496,23 @@ namespace libtorrent
|
||||||
add_job(j, false);
|
add_job(j, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
l.lock();
|
{
|
||||||
m_generic_io_jobs.m_job_cond.notify_all();
|
std::lock_guard<std::mutex> l(m_job_mutex);
|
||||||
m_generic_threads.job_queued(m_generic_io_jobs.m_queued_jobs.size());
|
m_generic_io_jobs.m_job_cond.notify_all();
|
||||||
l.unlock();
|
m_generic_threads.job_queued(m_generic_io_jobs.m_queued_jobs.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::mutex> l(m_completed_jobs_mutex);
|
std::lock_guard<std::mutex> l(m_completed_jobs_mutex);
|
||||||
|
|
||||||
bool const need_post = m_completed_jobs.size() == 0;
|
|
||||||
m_completed_jobs.append(jobs);
|
m_completed_jobs.append(jobs);
|
||||||
l.unlock();
|
|
||||||
|
|
||||||
if (need_post)
|
if (!m_job_completions_in_flight)
|
||||||
{
|
{
|
||||||
#if DEBUG_DISK_THREAD
|
|
||||||
// we take this lock just to make the logging prettier (non-interleaved)
|
// we take this lock just to make the logging prettier (non-interleaved)
|
||||||
DLOG("posting job handlers (%d)\n", m_completed_jobs.size());
|
DLOG("posting job handlers (%d)\n", m_completed_jobs.size());
|
||||||
#endif
|
|
||||||
m_ios.post(std::bind(&disk_io_thread::call_job_handlers, this, m_userdata));
|
m_ios.post(std::bind(&disk_io_thread::call_job_handlers, this, m_userdata));
|
||||||
|
m_job_completions_in_flight = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3454,9 +3524,10 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_completed_jobs_mutex);
|
std::unique_lock<std::mutex> l(m_completed_jobs_mutex);
|
||||||
|
|
||||||
#if DEBUG_DISK_THREAD
|
|
||||||
DLOG("call_job_handlers (%d)\n", m_completed_jobs.size());
|
DLOG("call_job_handlers (%d)\n", m_completed_jobs.size());
|
||||||
#endif
|
|
||||||
|
TORRENT_ASSERT(m_job_completions_in_flight);
|
||||||
|
m_job_completions_in_flight = false;
|
||||||
|
|
||||||
int const num_jobs = m_completed_jobs.size();
|
int const num_jobs = m_completed_jobs.size();
|
||||||
disk_io_job* j = m_completed_jobs.get_all();
|
disk_io_job* j = m_completed_jobs.get_all();
|
||||||
|
|
|
@ -98,6 +98,7 @@ const rlim_t rlim_infinity = RLIM_INFINITY;
|
||||||
#include "libtorrent/platform_util.hpp"
|
#include "libtorrent/platform_util.hpp"
|
||||||
#include "libtorrent/aux_/bind_to_device.hpp"
|
#include "libtorrent/aux_/bind_to_device.hpp"
|
||||||
#include "libtorrent/hex.hpp" // to_hex, from_hex
|
#include "libtorrent/hex.hpp" // to_hex, from_hex
|
||||||
|
#include "libtorrent/aux_/scope_end.hpp"
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
|
||||||
|
@ -4536,21 +4537,24 @@ namespace aux {
|
||||||
|
|
||||||
void session_impl::async_add_torrent(add_torrent_params* params)
|
void session_impl::async_add_torrent(add_torrent_params* params)
|
||||||
{
|
{
|
||||||
|
std::unique_ptr<add_torrent_params> holder(params);
|
||||||
|
|
||||||
if (string_begins_no_case("file://", params->url.c_str()) && !params->ti)
|
if (string_begins_no_case("file://", params->url.c_str()) && !params->ti)
|
||||||
{
|
{
|
||||||
m_disk_thread.async_load_torrent(params
|
m_disk_thread.async_load_torrent(params
|
||||||
, std::bind(&session_impl::on_async_load_torrent, this, _1));
|
, std::bind(&session_impl::on_async_load_torrent, this, _1));
|
||||||
|
holder.release();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
add_torrent(*params, ec);
|
add_torrent(*params, ec);
|
||||||
delete params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::on_async_load_torrent(disk_io_job const* j)
|
void session_impl::on_async_load_torrent(disk_io_job const* j)
|
||||||
{
|
{
|
||||||
add_torrent_params* params = reinterpret_cast<add_torrent_params*>(j->requester);
|
add_torrent_params* params = reinterpret_cast<add_torrent_params*>(j->requester);
|
||||||
|
std::unique_ptr<add_torrent_params> holder(params);
|
||||||
if (j->error.ec)
|
if (j->error.ec)
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<add_torrent_alert>(torrent_handle()
|
m_alerts.emplace_alert<add_torrent_alert>(torrent_handle()
|
||||||
|
@ -4564,8 +4568,6 @@ namespace aux {
|
||||||
error_code ec;
|
error_code ec;
|
||||||
add_torrent(*params, ec);
|
add_torrent(*params, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||||
|
@ -4587,6 +4589,11 @@ namespace aux {
|
||||||
// params is updated by add_torrent_impl()
|
// params is updated by add_torrent_impl()
|
||||||
add_torrent_params params = p;
|
add_torrent_params params = p;
|
||||||
std::shared_ptr<torrent> torrent_ptr;
|
std::shared_ptr<torrent> torrent_ptr;
|
||||||
|
|
||||||
|
// in case there's an error, make sure to abort the torrent before leaving
|
||||||
|
// the scope
|
||||||
|
auto abort_torrent = aux::scope_end([&]{ if (torrent_ptr) torrent_ptr->abort(); });
|
||||||
|
|
||||||
bool added;
|
bool added;
|
||||||
std::tie(torrent_ptr, added) = add_torrent_impl(params, ec);
|
std::tie(torrent_ptr, added) = add_torrent_impl(params, ec);
|
||||||
|
|
||||||
|
@ -4634,7 +4641,7 @@ namespace aux {
|
||||||
if (m_next_dht_torrent != m_torrents.end())
|
if (m_next_dht_torrent != m_torrents.end())
|
||||||
next_dht = m_next_dht_torrent->first;
|
next_dht = m_next_dht_torrent->first;
|
||||||
#endif
|
#endif
|
||||||
float load_factor = m_torrents.load_factor();
|
float const load_factor = m_torrents.load_factor();
|
||||||
|
|
||||||
m_torrents.insert(std::make_pair(params.info_hash, torrent_ptr));
|
m_torrents.insert(std::make_pair(params.info_hash, torrent_ptr));
|
||||||
|
|
||||||
|
@ -4647,6 +4654,10 @@ namespace aux {
|
||||||
m_obfuscated_torrents.insert(std::make_pair(h.final(), torrent_ptr));
|
m_obfuscated_torrents.insert(std::make_pair(h.final(), torrent_ptr));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// once we successfully add the torrent, we can disarm the abort action
|
||||||
|
abort_torrent.disarm();
|
||||||
|
torrent_ptr->added();
|
||||||
|
|
||||||
// if this insert made the hash grow, the iterators became invalid
|
// if this insert made the hash grow, the iterators became invalid
|
||||||
// we need to reset them
|
// we need to reset them
|
||||||
if (m_torrents.load_factor() < load_factor)
|
if (m_torrents.load_factor() < load_factor)
|
||||||
|
@ -4991,6 +5002,7 @@ namespace aux {
|
||||||
++m_next_lsd_torrent;
|
++m_next_lsd_torrent;
|
||||||
|
|
||||||
m_torrents.erase(i);
|
m_torrents.erase(i);
|
||||||
|
tptr->removed();
|
||||||
|
|
||||||
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
||||||
static char const req2[4] = {'r', 'e', 'q', '2'};
|
static char const req2[4] = {'r', 'e', 'q', '2'};
|
||||||
|
@ -5755,8 +5767,7 @@ namespace aux {
|
||||||
// this is not allowed to be the network thread!
|
// this is not allowed to be the network thread!
|
||||||
// TORRENT_ASSERT(is_not_thread());
|
// TORRENT_ASSERT(is_not_thread());
|
||||||
|
|
||||||
TORRENT_ASSERT(m_torrents.empty());
|
// TODO: asserts that no outstanding async operations are still in flight
|
||||||
TORRENT_ASSERT(m_connections.empty());
|
|
||||||
|
|
||||||
#if defined TORRENT_ASIO_DEBUGGING
|
#if defined TORRENT_ASIO_DEBUGGING
|
||||||
FILE* f = fopen("wakeups.log", "w+");
|
FILE* f = fopen("wakeups.log", "w+");
|
||||||
|
@ -6665,8 +6676,9 @@ namespace aux {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int torrent_state_gauges[counters::num_error_torrents - counters::num_checking_torrents + 1];
|
int const num_gauges = counters::num_error_torrents - counters::num_checking_torrents + 1;
|
||||||
memset(torrent_state_gauges, 0, sizeof(torrent_state_gauges));
|
std::array<int, num_gauges> torrent_state_gauges;
|
||||||
|
torrent_state_gauges.fill(0);
|
||||||
|
|
||||||
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
||||||
|
|
||||||
|
@ -6676,15 +6688,18 @@ namespace aux {
|
||||||
int num_active_downloading = 0;
|
int num_active_downloading = 0;
|
||||||
int num_active_finished = 0;
|
int num_active_finished = 0;
|
||||||
int total_downloaders = 0;
|
int total_downloaders = 0;
|
||||||
for (torrent_map::const_iterator i = m_torrents.begin()
|
for (auto const& tor : m_torrents)
|
||||||
, end(m_torrents.end()); i != end; ++i)
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<torrent> t = i->second;
|
std::shared_ptr<torrent> const& t = tor.second;
|
||||||
if (t->want_peers_download()) ++num_active_downloading;
|
if (t->want_peers_download()) ++num_active_downloading;
|
||||||
if (t->want_peers_finished()) ++num_active_finished;
|
if (t->want_peers_finished()) ++num_active_finished;
|
||||||
TORRENT_ASSERT(!(t->want_peers_download() && t->want_peers_finished()));
|
TORRENT_ASSERT(!(t->want_peers_download() && t->want_peers_finished()));
|
||||||
|
|
||||||
++torrent_state_gauges[t->current_stats_state() - counters::num_checking_torrents];
|
int const state = t->current_stats_state() - counters::num_checking_torrents;
|
||||||
|
if (state != torrent::no_gauge_state)
|
||||||
|
{
|
||||||
|
++torrent_state_gauges[state];
|
||||||
|
}
|
||||||
|
|
||||||
int pos = t->queue_position();
|
int pos = t->queue_position();
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
|
|
|
@ -189,6 +189,7 @@ namespace libtorrent
|
||||||
, m_files_checked(false)
|
, m_files_checked(false)
|
||||||
, m_storage_mode(p.storage_mode)
|
, m_storage_mode(p.storage_mode)
|
||||||
, m_announcing(false)
|
, m_announcing(false)
|
||||||
|
, m_added(false)
|
||||||
, m_active_time(0)
|
, m_active_time(0)
|
||||||
, m_finished_time(0)
|
, m_finished_time(0)
|
||||||
, m_sequential_download(false)
|
, m_sequential_download(false)
|
||||||
|
@ -499,7 +500,8 @@ namespace libtorrent
|
||||||
|
|
||||||
int torrent::current_stats_state() const
|
int torrent::current_stats_state() const
|
||||||
{
|
{
|
||||||
if (m_abort) return counters::num_checking_torrents + no_gauge_state;
|
if (m_abort || !m_added)
|
||||||
|
return counters::num_checking_torrents + no_gauge_state;
|
||||||
|
|
||||||
if (has_error()) return counters::num_error_torrents;
|
if (has_error()) return counters::num_error_torrents;
|
||||||
if (m_paused || m_graceful_pause_mode)
|
if (m_paused || m_graceful_pause_mode)
|
||||||
|
@ -521,7 +523,7 @@ namespace libtorrent
|
||||||
|
|
||||||
void torrent::update_gauge()
|
void torrent::update_gauge()
|
||||||
{
|
{
|
||||||
int new_gauge_state = current_stats_state() - counters::num_checking_torrents;
|
int const new_gauge_state = current_stats_state() - counters::num_checking_torrents;
|
||||||
TORRENT_ASSERT(new_gauge_state >= 0);
|
TORRENT_ASSERT(new_gauge_state >= 0);
|
||||||
TORRENT_ASSERT(new_gauge_state <= no_gauge_state);
|
TORRENT_ASSERT(new_gauge_state <= no_gauge_state);
|
||||||
|
|
||||||
|
@ -790,7 +792,8 @@ namespace libtorrent
|
||||||
|
|
||||||
torrent::~torrent()
|
torrent::~torrent()
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_abort);
|
// TODO: 3 assert there are no outstanding async operations on this
|
||||||
|
// torrent
|
||||||
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
for (int i = 0; i < aux::session_interface::num_torrent_lists; ++i)
|
for (int i = 0; i < aux::session_interface::num_torrent_lists; ++i)
|
||||||
|
@ -815,7 +818,6 @@ namespace libtorrent
|
||||||
// network thread cannot be maintained
|
// network thread cannot be maintained
|
||||||
|
|
||||||
TORRENT_ASSERT(m_peer_class == 0);
|
TORRENT_ASSERT(m_peer_class == 0);
|
||||||
TORRENT_ASSERT(m_abort);
|
|
||||||
TORRENT_ASSERT(m_connections.empty());
|
TORRENT_ASSERT(m_connections.empty());
|
||||||
if (!m_connections.empty())
|
if (!m_connections.empty())
|
||||||
disconnect_all(errors::torrent_aborted, op_bittorrent);
|
disconnect_all(errors::torrent_aborted, op_bittorrent);
|
||||||
|
@ -1892,15 +1894,15 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif // TORRENT_DISABLE_MUTABLE_TORRENTS
|
#endif // TORRENT_DISABLE_MUTABLE_TORRENTS
|
||||||
|
|
||||||
|
m_ses.disk_thread().async_check_files(
|
||||||
|
m_storage.get(), m_add_torrent_params ? m_add_torrent_params.get() : nullptr
|
||||||
|
, links, std::bind(&torrent::on_resume_data_checked
|
||||||
|
, shared_from_this(), _1));
|
||||||
// async_check_files will gut links
|
// async_check_files will gut links
|
||||||
#if TORRENT_USE_ASSERTS
|
#if TORRENT_USE_ASSERTS
|
||||||
TORRENT_ASSERT(m_outstanding_check_files == false);
|
TORRENT_ASSERT(m_outstanding_check_files == false);
|
||||||
m_outstanding_check_files = true;
|
m_outstanding_check_files = true;
|
||||||
#endif
|
#endif
|
||||||
m_ses.disk_thread().async_check_files(
|
|
||||||
m_storage.get(), m_add_torrent_params ? m_add_torrent_params.get() : nullptr
|
|
||||||
, links, std::bind(&torrent::on_resume_data_checked
|
|
||||||
, shared_from_this(), _1));
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
debug_log("init, async_check_files");
|
debug_log("init, async_check_files");
|
||||||
#endif
|
#endif
|
||||||
|
@ -4287,7 +4289,6 @@ namespace libtorrent
|
||||||
void torrent::abort()
|
void torrent::abort()
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
if (m_abort) return;
|
if (m_abort) return;
|
||||||
|
|
||||||
|
|
|
@ -70,8 +70,14 @@ namespace libtorrent
|
||||||
void torrent_handle::async_call(Fun f, Args&&... a) const
|
void torrent_handle::async_call(Fun f, Args&&... a) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<torrent> t = m_torrent.lock();
|
std::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
TORRENT_ASSERT_PRECOND(t);
|
if (!t)
|
||||||
if (!t) return;
|
{
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
throw_invalid_handle();
|
||||||
|
#else
|
||||||
|
std::terminate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
session_impl& ses = static_cast<session_impl&>(t->session());
|
session_impl& ses = static_cast<session_impl&>(t->session());
|
||||||
ses.get_io_service().dispatch([=,&ses] ()
|
ses.get_io_service().dispatch([=,&ses] ()
|
||||||
{
|
{
|
||||||
|
@ -98,8 +104,14 @@ namespace libtorrent
|
||||||
void torrent_handle::sync_call(Fun f, Args&&... a) const
|
void torrent_handle::sync_call(Fun f, Args&&... a) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<torrent> t = m_torrent.lock();
|
std::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
TORRENT_ASSERT_PRECOND(t);
|
if (!t)
|
||||||
if (!t) return;
|
{
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
throw_invalid_handle();
|
||||||
|
#else
|
||||||
|
std::terminate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
session_impl& ses = static_cast<session_impl&>(t->session());
|
session_impl& ses = static_cast<session_impl&>(t->session());
|
||||||
|
|
||||||
// this is the flag to indicate the call has completed
|
// this is the flag to indicate the call has completed
|
||||||
|
@ -130,9 +142,12 @@ namespace libtorrent
|
||||||
Ret torrent_handle::sync_call_ret(Ret def, Fun f, Args&&... a) const
|
Ret torrent_handle::sync_call_ret(Ret def, Fun f, Args&&... a) const
|
||||||
{
|
{
|
||||||
std::shared_ptr<torrent> t = m_torrent.lock();
|
std::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
TORRENT_ASSERT_PRECOND(t);
|
|
||||||
Ret r = def;
|
Ret r = def;
|
||||||
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
if (!t) throw_invalid_handle();
|
||||||
|
#else
|
||||||
if (!t) return r;
|
if (!t) return r;
|
||||||
|
#endif
|
||||||
session_impl& ses = static_cast<session_impl&>(t->session());
|
session_impl& ses = static_cast<session_impl&>(t->session());
|
||||||
|
|
||||||
// this is the flag to indicate the call has completed
|
// this is the flag to indicate the call has completed
|
||||||
|
|
|
@ -60,14 +60,16 @@ namespace libtorrent
|
||||||
using namespace libtorrent::aux;
|
using namespace libtorrent::aux;
|
||||||
|
|
||||||
timeout_handler::timeout_handler(io_service& ios)
|
timeout_handler::timeout_handler(io_service& ios)
|
||||||
: m_completion_timeout(0)
|
: m_start_time(clock_type::now())
|
||||||
, m_start_time(clock_type::now())
|
|
||||||
, m_read_time(m_start_time)
|
, m_read_time(m_start_time)
|
||||||
, m_timeout(ios)
|
, m_timeout(ios)
|
||||||
, m_read_timeout(0)
|
|
||||||
, m_abort(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
timeout_handler::~timeout_handler()
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(m_outstanding_timer_wait == 0);
|
||||||
|
}
|
||||||
|
|
||||||
void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
|
void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
|
||||||
{
|
{
|
||||||
m_completion_timeout = completion_timeout;
|
m_completion_timeout = completion_timeout;
|
||||||
|
@ -92,6 +94,9 @@ namespace libtorrent
|
||||||
m_timeout.expires_at(m_read_time + seconds(timeout), ec);
|
m_timeout.expires_at(m_read_time + seconds(timeout), ec);
|
||||||
m_timeout.async_wait(std::bind(
|
m_timeout.async_wait(std::bind(
|
||||||
&timeout_handler::timeout_callback, shared_from_this(), _1));
|
&timeout_handler::timeout_callback, shared_from_this(), _1));
|
||||||
|
#if TORRENT_USE_ASSERTS
|
||||||
|
++m_outstanding_timer_wait;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void timeout_handler::restart_read_timeout()
|
void timeout_handler::restart_read_timeout()
|
||||||
|
@ -110,6 +115,10 @@ namespace libtorrent
|
||||||
void timeout_handler::timeout_callback(error_code const& error)
|
void timeout_handler::timeout_callback(error_code const& error)
|
||||||
{
|
{
|
||||||
COMPLETE_ASYNC("timeout_handler::timeout_callback");
|
COMPLETE_ASYNC("timeout_handler::timeout_callback");
|
||||||
|
#if TORRENT_USE_ASSERTS
|
||||||
|
TORRENT_ASSERT(m_outstanding_timer_wait > 0);
|
||||||
|
--m_outstanding_timer_wait;
|
||||||
|
#endif
|
||||||
if (m_abort) return;
|
if (m_abort) return;
|
||||||
|
|
||||||
time_point now = clock_type::now();
|
time_point now = clock_type::now();
|
||||||
|
@ -139,6 +148,9 @@ namespace libtorrent
|
||||||
m_timeout.expires_at(m_read_time + seconds(timeout), ec);
|
m_timeout.expires_at(m_read_time + seconds(timeout), ec);
|
||||||
m_timeout.async_wait(
|
m_timeout.async_wait(
|
||||||
std::bind(&timeout_handler::timeout_callback, shared_from_this(), _1));
|
std::bind(&timeout_handler::timeout_callback, shared_from_this(), _1));
|
||||||
|
#if TORRENT_USE_ASSERTS
|
||||||
|
++m_outstanding_timer_wait;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
tracker_connection::tracker_connection(
|
tracker_connection::tracker_connection(
|
||||||
|
@ -207,12 +219,10 @@ namespace libtorrent
|
||||||
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
|
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
|
||||||
, m_ses(ses)
|
, m_ses(ses)
|
||||||
#endif
|
#endif
|
||||||
, m_abort(false)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
tracker_manager::~tracker_manager()
|
tracker_manager::~tracker_manager()
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_abort);
|
|
||||||
abort_all_requests(true);
|
abort_all_requests(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue