From 5c361715da9d20d63b019d7fc4ce772cdecd7138 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 6 Oct 2016 00:08:14 -0400 Subject: [PATCH] handle exceptions in session and torrent io_service jobs (#1185) handle exceptions in session and torrent io_service jobs --- include/libtorrent/alert_types.hpp | 23 ++++- include/libtorrent/aux_/session_impl.hpp | 3 + include/libtorrent/torrent.hpp | 14 +-- include/libtorrent/torrent_status.hpp | 6 +- src/alert.cpp | 40 +++++++- src/disk_io_thread.cpp | 7 +- src/session_handle.cpp | 44 +++++++- src/session_impl.cpp | 85 ++++++++++------ src/torrent.cpp | 122 +++++++++++++++-------- src/torrent_handle.cpp | 48 ++++++++- 10 files changed, 295 insertions(+), 97 deletions(-) diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 69cc55711..917c098c6 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -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 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 diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index d8db59c90..2df5b88cc 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -207,6 +207,9 @@ namespace libtorrent plugins_dht_request_idx = 3 // dht_request_feature }; + template + void wrap(Fun f, Args&&... a); + #if TORRENT_USE_INVARIANT_CHECKS friend class libtorrent::invariant_access; #endif diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index fdcce5444..01c8b48ec 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -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 + 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 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 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; // ---- diff --git a/include/libtorrent/torrent_status.hpp b/include/libtorrent/torrent_status.hpp index 7c4368320..0da01edd1 100644 --- a/include/libtorrent/torrent_status.hpp +++ b/include/libtorrent/torrent_status.hpp @@ -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. diff --git a/src/alert.cpp b/src/alert.cpp index c3299bd5d..2b9e98173 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -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 + diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index d6b9b889f..a43b596d0 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -3509,7 +3509,7 @@ namespace libtorrent std::unique_lock 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 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(); diff --git a/src/session_handle.cpp b/src/session_handle.cpp index b88e2aa75..73c737fa1 100644 --- a/src/session_handle.cpp +++ b/src/session_handle.cpp @@ -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(e.code(), e.what()); + } catch (std::exception const& e) { + m_impl->alerts().emplace_alert(error_code(), e.what()); + } catch (...) { + m_impl->alerts().emplace_alert(error_code(), "unknown error"); + } +#endif + }); } template @@ -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 l(m_impl->mut); done = true; m_impl->cond.notify_all(); }); aux::torrent_wait(done, *m_impl); + if (ex) std::rethrow_exception(ex); } template @@ -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 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; } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 8805e7b8d..4dff12c49 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -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 + void session_impl::wrap(Fun f, Args&&... a) +#ifndef BOOST_NO_EXCEPTIONS + try +#endif + { + (this->*f)(std::forward(a)...); + } +#ifndef BOOST_NO_EXCEPTIONS + catch (system_error const& e) { + alerts().emplace_alert(e.code(), e.what()); + pause(); + } catch (std::exception const& e) { + alerts().emplace_alert(error_code(), e.what()); + pause(); + } catch (...) { + alerts().emplace_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(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 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* ret , std::function 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* ret - , std::uint32_t flags) const + , std::uint32_t const flags) const { - for (std::vector::iterator i - = ret->begin(), end(ret->end()); i != end; ++i) + for (auto& st : *ret) { - std::shared_ptr 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 } diff --git a/src/torrent.cpp b/src/torrent.cpp index a36b0e425..7f7d4665e 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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 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 p - , error_code const& e) - { - COMPLETE_ASYNC("tracker::on_tracker_announce_disp"); - std::shared_ptr 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 + void torrent::wrap(Fun f, Args&&... a) +#ifndef BOOST_NO_EXCEPTIONS + try +#endif + { + (this->*f)(std::forward(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(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(get_handle() + , error_code(), e.what()); + pause(); + } catch (...) { +#ifndef TORRENT_DISABLE_LOGGING + debug_log("EXCEPTION: unknown"); +#endif + alerts().emplace_alert(get_handle() + , error_code(), "unknown error"); + pause(); + } +#endif + void torrent::cancel_non_critical() { std::set 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::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
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
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
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 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 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 diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 11f52fd4c..728109b93 100644 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -73,7 +73,25 @@ namespace libtorrent TORRENT_ASSERT_PRECOND(t); if (!t) return; session_impl& ses = static_cast(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_handle(m_torrent) + , e.code(), e.what()); + } catch (std::exception const& e) { + ses.alerts().emplace_alert(torrent_handle(m_torrent) + , error_code(), e.what()); + } catch (...) { + ses.alerts().emplace_alert(torrent_handle(m_torrent) + , error_code(), "unknown error"); + } +#endif + } ); } template @@ -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 l(ses.mut); done = true; ses.cond.notify_all(); } ); aux::torrent_wait(done, ses); + if (ex) std::rethrow_exception(ex); } template @@ -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 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; }