handle exceptions in session and torrent io_service jobs (#1185)

handle exceptions in session and torrent io_service jobs
This commit is contained in:
Arvid Norberg 2016-10-06 00:08:14 -04:00 committed by GitHub
parent 3c355bb3f8
commit 5c361715da
10 changed files with 295 additions and 97 deletions

View File

@ -2396,11 +2396,32 @@ namespace libtorrent
int const m_num_blocks;
};
// this alert is posted when the session encounters a serious error,
// potentially fatal
struct TORRENT_EXPORT session_error_alert : alert
{
// internal
session_error_alert(aux::stack_allocator& alloc, error_code err
, string_view error_str);
TORRENT_DEFINE_ALERT(session_error_alert, 90)
static const int static_category = alert::error_notification;
std::string message() const override;
// The error code, if one is associated with this error
error_code error;
private:
std::reference_wrapper<aux::stack_allocator> m_alloc;
int const m_msg_idx;
};
#undef TORRENT_DEFINE_ALERT_IMPL
#undef TORRENT_DEFINE_ALERT
#undef TORRENT_DEFINE_ALERT_PRIO
enum { num_alert_types = 90 }; // this enum represents "max_alert_index" + 1
enum { num_alert_types = 91 }; // this enum represents "max_alert_index" + 1
}
#endif

View File

@ -207,6 +207,9 @@ namespace libtorrent
plugins_dht_request_idx = 3 // dht_request_feature
};
template <typename Fun, typename... Args>
void wrap(Fun f, Args&&... a);
#if TORRENT_USE_INVARIANT_CHECKS
friend class libtorrent::invariant_access;
#endif

View File

@ -971,6 +971,9 @@ namespace libtorrent
int time_since_complete() const { return int(time(0) - m_last_seen_complete); }
time_t last_seen_complete() const { return m_last_seen_complete; }
template <typename Fun, typename... Args>
void wrap(Fun f, Args&&... a);
// LOGGING
#ifndef TORRENT_DISABLE_LOGGING
virtual bool should_log() const override;
@ -1139,10 +1142,7 @@ namespace libtorrent
void update_tracker_timer(time_point now);
static void on_tracker_announce_disp(std::weak_ptr<torrent> p
, error_code const& e);
void on_tracker_announce();
void on_tracker_announce(error_code const& ec);
#ifndef TORRENT_DISABLE_DHT
static void on_dht_announce_response_disp(std::weak_ptr<torrent> t
@ -1433,10 +1433,10 @@ namespace libtorrent
// is is disabled while paused and checking files
bool m_announcing:1;
// this is true while the tracker deadline timer
// this is > 0 while the tracker deadline timer
// is in use. i.e. one or more trackers are waiting
// for a reannounce
bool m_waiting_tracker:1;
std::int8_t m_waiting_tracker = 0;
// ----
@ -1503,7 +1503,7 @@ namespace libtorrent
// these are the flags sent in on a call to save_resume_data
// we need to save them to check them in write_resume_data
std::uint8_t m_save_resume_flags;
std::uint8_t m_save_resume_flags = 0;
// ----

View File

@ -140,7 +140,11 @@ namespace libtorrent
// the error occurred while loading the .torrent file via the user
// supplied load function
error_file_metadata = -4
error_file_metadata = -4,
// there was a serious error reported in this torrent. The error code
// or a torrent log alert may provide more information.
error_file_exception = -5,
};
// the path to the directory where this torrent's files are stored.

View File

@ -1261,8 +1261,17 @@ namespace libtorrent {
std::string torrent_error_alert::message() const
{
char msg[200];
std::snprintf(msg, sizeof(msg), " ERROR: %s", convert_from_native(error.message()).c_str());
char msg[400];
if (error)
{
std::snprintf(msg, sizeof(msg), " ERROR: (%d %s) %s"
, error.value(), convert_from_native(error.message()).c_str()
, filename());
}
else
{
std::snprintf(msg, sizeof(msg), " ERROR: %s", filename());
}
return torrent_alert::message() + msg;
}
@ -1689,7 +1698,7 @@ namespace libtorrent {
std::string lsd_error_alert::message() const
{
return "Local Service Discovery error: " + error.message();
return "Local Service Discovery error: " + convert_from_native(error.message());
}
session_stats_alert::session_stats_alert(aux::stack_allocator&, counters const& cnt)
@ -2049,4 +2058,29 @@ namespace libtorrent {
return ret;
}
session_error_alert::session_error_alert(aux::stack_allocator& alloc
, error_code e, string_view error_str)
: error(e)
, m_alloc(alloc)
, m_msg_idx(alloc.copy_buffer(error_str))
{}
std::string session_error_alert::message() const
{
char buf[400];
if (error)
{
std::snprintf(buf, sizeof(buf), "session error: (%d %s) %s"
, error.value(), convert_from_native(error.message()).c_str()
, m_alloc.get().ptr(m_msg_idx));
}
else
{
std::snprintf(buf, sizeof(buf), "session error: %s"
, m_alloc.get().ptr(m_msg_idx));
}
return buf;
}
} // namespace libtorrent

View File

@ -3509,7 +3509,7 @@ namespace libtorrent
std::unique_lock<std::mutex> l(m_completed_jobs_mutex);
bool need_post = m_completed_jobs.size() == 0;
bool const need_post = m_completed_jobs.size() == 0;
m_completed_jobs.append(jobs);
l.unlock();
@ -3524,6 +3524,9 @@ namespace libtorrent
}
// This is run in the network thread
// TODO: 2 it would be nice to get rid of m_userdata and just have a function
// object to pass all the job completions to. It could in turn be responsible
// for posting them to the correct io_servive
void disk_io_thread::call_job_handlers(void* userdata)
{
std::unique_lock<std::mutex> l(m_completed_jobs_mutex);
@ -3532,7 +3535,7 @@ namespace libtorrent
DLOG("call_job_handlers (%d)\n", m_completed_jobs.size());
#endif
int num_jobs = m_completed_jobs.size();
int const num_jobs = m_completed_jobs.size();
disk_io_job* j = m_completed_jobs.get_all();
l.unlock();

View File

@ -49,7 +49,21 @@ namespace libtorrent
void session_handle::async_call(Fun f, Args&&... a) const
{
m_impl->get_io_service().dispatch([=]() mutable
{ (m_impl->*f)(a...); });
{
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
(m_impl->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
} catch (system_error const& e) {
m_impl->alerts().emplace_alert<session_error_alert>(e.code(), e.what());
} catch (std::exception const& e) {
m_impl->alerts().emplace_alert<session_error_alert>(error_code(), e.what());
} catch (...) {
m_impl->alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
}
#endif
});
}
template<typename Fun, typename... Args>
@ -60,15 +74,25 @@ namespace libtorrent
// and simplify the capture expression
bool done = false;
m_impl->get_io_service().dispatch([=,&done]() mutable
std::exception_ptr ex;
m_impl->get_io_service().dispatch([=,&done,&ex]() mutable
{
(m_impl->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
(m_impl->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
} catch (...) {
ex = std::current_exception();
}
#endif
std::unique_lock<std::mutex> l(m_impl->mut);
done = true;
m_impl->cond.notify_all();
});
aux::torrent_wait(done, *m_impl);
if (ex) std::rethrow_exception(ex);
}
template<typename Ret, typename Fun, typename... Args>
@ -79,15 +103,25 @@ namespace libtorrent
// and simplify the capture expression
bool done = false;
Ret r;
m_impl->get_io_service().dispatch([=,&r,&done]() mutable
std::exception_ptr ex;
m_impl->get_io_service().dispatch([=,&r,&done,&ex]() mutable
{
r = (m_impl->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
r = (m_impl->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
} catch (...) {
ex = std::current_exception();
}
#endif
std::unique_lock<std::mutex> l(m_impl->mut);
done = true;
m_impl->cond.notify_all();
});
aux::torrent_wait(done, *m_impl);
if (ex) std::rethrow_exception(ex);
return r;
}

View File

@ -195,6 +195,7 @@ namespace libtorrent {
namespace aux {
// TODO: 3 move this out of this file
#ifndef TORRENT_DISABLE_DHT
dht_settings read_dht_settings(bdecode_node const& e)
{
@ -443,6 +444,27 @@ namespace aux {
update_time_now();
}
template <typename Fun, typename... Args>
void session_impl::wrap(Fun f, Args&&... a)
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
(this->*f)(std::forward<Args>(a)...);
}
#ifndef BOOST_NO_EXCEPTIONS
catch (system_error const& e) {
alerts().emplace_alert<session_error_alert>(e.code(), e.what());
pause();
} catch (std::exception const& e) {
alerts().emplace_alert<session_error_alert>(error_code(), e.what());
pause();
} catch (...) {
alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
pause();
}
#endif
// This function is called by the creating thread, not in the message loop's
// io_service thread.
// TODO: 2 is there a reason not to move all of this into init()? and just
@ -520,8 +542,10 @@ namespace aux {
}
#endif
// TODO: 3 make this move all the way through to the init() call
// if we're in C++14
auto copy = std::make_shared<settings_pack>(std::move(pack));
m_io_service.post(std::bind(&session_impl::init, this, copy));
m_io_service.post([this, copy] { this->wrap(&session_impl::init, copy); });
}
void session_impl::init(std::shared_ptr<settings_pack> pack)
@ -566,15 +590,15 @@ namespace aux {
async_inc_threads();
add_outstanding_async("session_impl::on_tick");
#endif
error_code ec;
m_io_service.post(std::bind(&session_impl::on_tick, this, ec));
m_io_service.post([this]{ this->wrap(&session_impl::on_tick, error_code()); });
error_code ec;
ADD_OUTSTANDING_ASYNC("session_impl::on_lsd_announce");
int delay = (std::max)(m_settings.get_int(settings_pack::local_service_announce_interval)
/ (std::max)(int(m_torrents.size()), 1), 1);
int const delay = std::max(m_settings.get_int(settings_pack::local_service_announce_interval)
/ std::max(int(m_torrents.size()), 1), 1);
m_lsd_announce_timer.expires_from_now(seconds(delay), ec);
m_lsd_announce_timer.async_wait(
std::bind(&session_impl::on_lsd_announce, this, _1));
m_lsd_announce_timer.async_wait([this](error_code const& e) {
this->wrap(&session_impl::on_lsd_announce, e); } );
TORRENT_ASSERT(!ec);
#ifndef TORRENT_DISABLE_LOGGING
@ -1339,7 +1363,7 @@ namespace aux {
{
if (m_deferred_submit_disk_jobs) return;
m_deferred_submit_disk_jobs = true;
m_io_service.post(std::bind(&session_impl::submit_disk_jobs, this));
m_io_service.post([this] { this->wrap(&session_impl::submit_disk_jobs); } );
}
void session_impl::submit_disk_jobs()
@ -3136,7 +3160,8 @@ namespace aux {
ADD_OUTSTANDING_ASYNC("session_impl::on_tick");
error_code ec;
m_timer.expires_at(now + milliseconds(m_settings.get_int(settings_pack::tick_interval)), ec);
m_timer.async_wait(make_tick_handler(std::bind(&session_impl::on_tick, this, _1)));
m_timer.async_wait(make_tick_handler([this](error_code const& err) {
this->wrap(&session_impl::on_tick, err); }));
m_download_rate.update_quotas(now - m_last_tick);
m_upload_rate.update_quotas(now - m_last_tick);
@ -3525,8 +3550,8 @@ namespace aux {
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
error_code ec;
m_dht_announce_timer.expires_from_now(seconds(0), ec);
m_dht_announce_timer.async_wait(
std::bind(&session_impl::on_dht_announce, this, _1));
m_dht_announce_timer.async_wait([this](error_code const& err) {
this->wrap(&session_impl::on_dht_announce, err); });
}
}
@ -3577,8 +3602,9 @@ namespace aux {
ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
error_code ec;
m_dht_announce_timer.expires_from_now(seconds(delay), ec);
m_dht_announce_timer.async_wait(
std::bind(&session_impl::on_dht_announce, this, _1));
m_dht_announce_timer.async_wait([this](error_code const& err) {
this->wrap(&session_impl::on_dht_announce, err); }
);
if (!m_dht_torrents.empty())
{
@ -3623,8 +3649,8 @@ namespace aux {
/ (std::max)(int(m_torrents.size()), 1), 1);
error_code ec;
m_lsd_announce_timer.expires_from_now(seconds(delay), ec);
m_lsd_announce_timer.async_wait(
std::bind(&session_impl::on_lsd_announce, this, _1));
m_lsd_announce_timer.async_wait([this](error_code const& err) {
this->wrap(&session_impl::on_lsd_announce, err); });
if (m_torrents.empty()) return;
@ -4358,6 +4384,8 @@ namespace aux {
void session_impl::set_queue_position(torrent* me, int p)
{
// TODO: Maybe the queue position should be maintained as a vector of
// torrent pointers. Maybe this logic could be simplified
if (p >= 0 && me->queue_position() == -1)
{
for (session_impl::torrent_map::iterator i = m_torrents.begin()
@ -4531,29 +4559,26 @@ namespace aux {
void session_impl::get_torrent_status(std::vector<torrent_status>* ret
, std::function<bool(torrent_status const&)> const& pred
, std::uint32_t flags) const
, std::uint32_t const flags) const
{
for (torrent_map::const_iterator i
= m_torrents.begin(), end(m_torrents.end());
i != end; ++i)
for (auto const& t : m_torrents)
{
if (i->second->is_aborted()) continue;
if (t.second->is_aborted()) continue;
torrent_status st;
i->second->status(&st, flags);
t.second->status(&st, flags);
if (!pred(st)) continue;
ret->push_back(st);
ret->push_back(std::move(st));
}
}
void session_impl::refresh_torrent_status(std::vector<torrent_status>* ret
, std::uint32_t flags) const
, std::uint32_t const flags) const
{
for (std::vector<torrent_status>::iterator i
= ret->begin(), end(ret->end()); i != end; ++i)
for (auto& st : *ret)
{
std::shared_ptr<torrent> t = i->handle.m_torrent.lock();
auto t = st.handle.m_torrent.lock();
if (!t) continue;
t->status(&*i, flags);
t->status(&st, flags);
}
}
@ -6183,7 +6208,7 @@ namespace aux {
m_pending_auto_manage = true;
m_need_auto_manage = true;
m_io_service.post(std::bind(&session_impl::on_trigger_auto_manage, this));
m_io_service.post([this]{ this->wrap(&session_impl::on_trigger_auto_manage); });
}
void session_impl::on_trigger_auto_manage()
@ -6256,8 +6281,8 @@ namespace aux {
int delay = (std::max)(m_settings.get_int(settings_pack::dht_announce_interval)
/ (std::max)(int(m_torrents.size()), 1), 1);
m_dht_announce_timer.expires_from_now(seconds(delay), ec);
m_dht_announce_timer.async_wait(
std::bind(&session_impl::on_dht_announce, this, _1));
m_dht_announce_timer.async_wait([this](error_code const& e) {
this->wrap(&session_impl::on_dht_announce, e); });
#endif
}

View File

@ -189,7 +189,6 @@ namespace libtorrent
, m_files_checked(false)
, m_storage_mode(p.storage_mode)
, m_announcing(false)
, m_waiting_tracker(false)
, m_active_time(0)
, m_finished_time(0)
, m_sequential_download(false)
@ -200,7 +199,6 @@ namespace libtorrent
, m_need_save_resume_data((p.flags & add_torrent_params::flag_need_save_resume) != 0)
, m_seeding_time(0)
, m_max_uploads((1<<24)-1)
, m_save_resume_flags(0)
, m_num_uploads(0)
, m_need_connect_boost(true)
, m_lsd_seq(0)
@ -424,7 +422,7 @@ namespace libtorrent
// as we replace the torrent_info object
// we're about to erase the session's reference to this
// torrent, create another reference
std::shared_ptr<torrent> me(shared_from_this());
auto me = shared_from_this();
m_ses.remove_torrent_impl(me, 0);
@ -1804,7 +1802,8 @@ namespace libtorrent
if (m_seed_mode)
{
m_have_all = true;
m_ses.get_io_service().post(std::bind(&torrent::files_checked, shared_from_this()));
auto self = shared_from_this();
m_ses.get_io_service().post([self] { self->wrap(&torrent::files_checked); });
TORRENT_ASSERT(m_outstanding_check_files == false);
m_add_torrent_params.reset();
update_gauge();
@ -2667,21 +2666,13 @@ namespace libtorrent
}
#endif
void torrent::on_tracker_announce_disp(std::weak_ptr<torrent> p
, error_code const& e)
{
COMPLETE_ASYNC("tracker::on_tracker_announce_disp");
std::shared_ptr<torrent> t = p.lock();
if (!t) return;
t->m_waiting_tracker = false;
if (e) return;
t->on_tracker_announce();
}
void torrent::on_tracker_announce()
void torrent::on_tracker_announce(error_code const& ec)
{
COMPLETE_ASYNC("tracker::on_tracker_announce");
TORRENT_ASSERT(is_single_thread());
TORRENT_ASSERT(m_waiting_tracker > 0);
--m_waiting_tracker;
if (ec) return;
if (m_abort) return;
announce_with_tracker();
}
@ -3501,7 +3492,7 @@ namespace libtorrent
time_point torrent::next_announce() const
{
return m_waiting_tracker?m_tracker_timer.expires_at():min_time();
return m_waiting_tracker ? m_tracker_timer.expires_at() : min_time();
}
// this is the entry point for the client to force a re-announce. It's
@ -4065,9 +4056,7 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_EXTENSIONS
for (auto& ext : m_extensions)
{
TORRENT_TRY {
ext->on_piece_pass(index);
} TORRENT_CATCH (std::exception const&) {}
ext->on_piece_pass(index);
}
#endif
@ -4270,9 +4259,7 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_EXTENSIONS
for (auto& ext : m_extensions)
{
TORRENT_TRY {
ext->on_piece_failed(index);
} TORRENT_CATCH (std::exception const&) {}
ext->on_piece_failed(index);
}
#endif
@ -4743,6 +4730,42 @@ namespace libtorrent
return detail::read_uint32(ptr);
}
template <typename Fun, typename... Args>
void torrent::wrap(Fun f, Args&&... a)
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
(this->*f)(std::forward<Args>(a)...);
}
#ifndef BOOST_NO_EXCEPTIONS
catch (system_error const& e) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: (%d %s) %s"
, e.code().value()
, e.code().message().c_str()
, e.what());
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, e.code(), e.what());
pause();
} catch (std::exception const& e) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: %s", e.what());
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, error_code(), e.what());
pause();
} catch (...) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: unknown");
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, error_code(), "unknown error");
pause();
}
#endif
void torrent::cancel_non_critical()
{
std::set<int> time_critical;
@ -4810,9 +4833,10 @@ namespace libtorrent
if (m_time_critical_pieces.empty())
{
// defer this by posting it to the end of the message queue.
// this gives the client a chance to specify multiple time critical
// this gives the client a chance to specify multiple time-critical
// pieces before libtorrent cancels requests
m_ses.get_io_service().post(std::bind(&torrent::cancel_non_critical, this));
auto self = shared_from_this();
m_ses.get_io_service().post([self] { self->wrap(&torrent::cancel_non_critical); });
}
for (std::vector<time_critical_piece>::iterator i = m_time_critical_pieces.begin()
@ -5941,11 +5965,16 @@ namespace libtorrent
debug_log("resolving proxy for web seed: %s", web->url.c_str());
#endif
auto self = shared_from_this();
std::uint16_t const proxy_port = ps.port;
// use proxy
web->resolving = true;
m_ses.async_resolve(ps.hostname, resolver_interface::abort_on_shutdown
, std::bind(&torrent::on_proxy_name_lookup, shared_from_this()
, _1, _2, web, ps.port));
, [self,web,proxy_port](error_code const& e, std::vector<address> const& addrs)
{
self->wrap(&torrent::on_proxy_name_lookup, e, addrs, web, proxy_port);
});
}
else if (ps.proxy_hostnames
&& (ps.type == settings_pack::socks5
@ -5960,10 +5989,14 @@ namespace libtorrent
debug_log("resolving web seed: \"%s\" %s", hostname.c_str(), web->url.c_str());
#endif
auto self = shared_from_this();
web->resolving = true;
m_ses.async_resolve(hostname, resolver_interface::abort_on_shutdown
, std::bind(&torrent::on_name_lookup, shared_from_this(), _1, _2
, port, web));
, [self,web,port](error_code const& e, std::vector<address> const& addrs)
{
self->wrap(&torrent::on_name_lookup, e, addrs, port, web);
});
}
}
@ -6043,10 +6076,13 @@ namespace libtorrent
return;
}
auto self = shared_from_this();
web->resolving = true;
m_ses.async_resolve(hostname, resolver_interface::abort_on_shutdown
, std::bind(&torrent::on_name_lookup, shared_from_this(), _1, _2
, port, web));
, [self,web,port](error_code const& err, std::vector<address> const& addr)
{
self->wrap(&torrent::on_name_lookup, err, addr, port, web);
});
}
void torrent::on_name_lookup(error_code const& e
@ -9209,16 +9245,17 @@ namespace libtorrent
#endif
// don't re-issue the timer if it's the same expiration time as last time
// if m_waiting_tracker is false, expires_at() is undefined
// if m_waiting_tracker is 0, expires_at() is undefined
if (m_waiting_tracker && m_tracker_timer.expires_at() == next_announce) return;
m_waiting_tracker = true;
error_code ec;
std::weak_ptr<torrent> self(shared_from_this());
auto self = shared_from_this();
ADD_OUTSTANDING_ASYNC("tracker::on_tracker_announce_disp");
m_tracker_timer.expires_at(next_announce, ec);
m_tracker_timer.async_wait(std::bind(&torrent::on_tracker_announce_disp, self, _1));
ADD_OUTSTANDING_ASYNC("tracker::on_tracker_announce");
++m_waiting_tracker;
m_tracker_timer.async_wait([self](error_code const& e)
{ self->wrap(&torrent::on_tracker_announce, e); });
}
void torrent::start_announcing()
@ -9337,7 +9374,7 @@ namespace libtorrent
TORRENT_ASSERT(is_single_thread());
INVARIANT_CHECK;
std::weak_ptr<torrent> self(shared_from_this());
auto self = shared_from_this();
#ifndef TORRENT_DISABLE_EXTENSIONS
for (auto const& ext : m_extensions)
@ -9499,13 +9536,12 @@ namespace libtorrent
if (settings().get_bool(settings_pack::dont_count_slow_torrents))
{
if (is_inactive != m_inactive
&& !m_pending_active_change)
if (is_inactive != m_inactive && !m_pending_active_change)
{
int delay = settings().get_int(settings_pack::auto_manage_startup);
int const delay = settings().get_int(settings_pack::auto_manage_startup);
m_inactivity_timer.expires_from_now(seconds(delay));
m_inactivity_timer.async_wait(std::bind(&torrent::on_inactivity_tick
, shared_from_this(), _1));
m_inactivity_timer.async_wait([self](error_code const& ec) {
self->wrap(&torrent::on_inactivity_tick, ec); });
m_pending_active_change = true;
}
else if (is_inactive == m_inactive

View File

@ -73,7 +73,25 @@ namespace libtorrent
TORRENT_ASSERT_PRECOND(t);
if (!t) return;
session_impl& ses = static_cast<session_impl&>(t->session());
ses.get_io_service().dispatch([=] () { (t.get()->*f)(a...); } );
ses.get_io_service().dispatch([=,&ses] ()
{
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
(t.get()->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
} catch (system_error const& e) {
ses.alerts().emplace_alert<torrent_error_alert>(torrent_handle(m_torrent)
, e.code(), e.what());
} catch (std::exception const& e) {
ses.alerts().emplace_alert<torrent_error_alert>(torrent_handle(m_torrent)
, error_code(), e.what());
} catch (...) {
ses.alerts().emplace_alert<torrent_error_alert>(torrent_handle(m_torrent)
, error_code(), "unknown error");
}
#endif
} );
}
template<typename Fun, typename... Args>
@ -87,15 +105,25 @@ namespace libtorrent
// this is the flag to indicate the call has completed
bool done = false;
ses.get_io_service().dispatch([=,&done,&ses] ()
std::exception_ptr ex;
ses.get_io_service().dispatch([=,&done,&ses,&ex] ()
{
(t.get()->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
(t.get()->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
} catch (...) {
ex = std::current_exception();
}
#endif
std::unique_lock<std::mutex> l(ses.mut);
done = true;
ses.cond.notify_all();
} );
aux::torrent_wait(done, ses);
if (ex) std::rethrow_exception(ex);
}
template<typename Ret, typename Fun, typename... Args>
@ -110,9 +138,18 @@ namespace libtorrent
// this is the flag to indicate the call has completed
bool done = false;
ses.get_io_service().dispatch([=,&r,&done,&ses] ()
std::exception_ptr ex;
ses.get_io_service().dispatch([=,&r,&done,&ses,&ex] ()
{
r = (t.get()->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
try {
#endif
r = (t.get()->*f)(a...);
#ifndef BOOST_NO_EXCEPTIONS
} catch (...) {
ex = std::current_exception();
}
#endif
std::unique_lock<std::mutex> l(ses.mut);
done = true;
ses.cond.notify_all();
@ -120,6 +157,7 @@ namespace libtorrent
aux::torrent_wait(done, ses);
if (ex) std::rethrow_exception(ex);
return r;
}