From fd51412b70ea0fc7f1fb8e4881886e4415b49a8e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 2 Nov 2007 00:27:53 +0000 Subject: [PATCH] shutdown improvements. Fixes stall --- include/libtorrent/tracker_manager.hpp | 1 + src/connection_queue.cpp | 8 +- src/http_tracker_connection.cpp | 6 ++ src/session_impl.cpp | 137 +++++++++---------------- src/tracker_manager.cpp | 20 ++-- 5 files changed, 76 insertions(+), 96 deletions(-) diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index 2c9ceeaef..fdc3f6bbf 100755 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -184,6 +184,7 @@ namespace libtorrent typedef boost::mutex mutex_t; mutable mutex_t m_mutex; + bool m_abort; }; struct TORRENT_EXPORT tracker_connection diff --git a/src/connection_queue.cpp b/src/connection_queue.cpp index c204b5a34..a48456ed5 100644 --- a/src/connection_queue.cpp +++ b/src/connection_queue.cpp @@ -116,8 +116,14 @@ namespace libtorrent { INVARIANT_CHECK; - if (!free_slots() || m_queue.empty()) + if (!free_slots()) return; + + if (m_queue.empty()) + { + m_timer.cancel(); + return; + } std::list::iterator i = std::find_if(m_queue.begin() , m_queue.end(), boost::bind(&entry::connecting, _1) == false); diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index a5c542b44..ed9823b83 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -514,6 +514,12 @@ namespace libtorrent m_connection_ticket = -1; m_timed_out = true; tracker_connection::close(); +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr cb = requester(); + std::stringstream msg; + msg << "http_tracker_connection::close() " << m_man.num_requests(); + if (cb) cb->debug_log(msg.str()); +#endif } void http_tracker_connection::name_lookup(asio::error_code const& error diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 5b348b26c..0828578f0 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -693,21 +693,61 @@ namespace detail i->second->abort(); } -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " aborting all connections\n"; -#endif - // abort all connections - for (connection_map::iterator i = m_connections.begin() - , end(m_connections.end()); i != end; ++i) - { - (*i)->disconnect(); - } - #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " aborting all tracker requests\n"; #endif m_tracker_manager.abort_all_requests(); +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << time_now_string() << " sending event=stopped to trackers\n"; + int counter = 0; +#endif + for (torrent_map::iterator i = m_torrents.begin(); + i != m_torrents.end(); ++i) + { + torrent& t = *i->second; + + if ((!t.is_paused() || t.should_request()) + && !t.trackers().empty()) + { +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + ++counter; +#endif + tracker_request req = t.generate_tracker_request(); + TORRENT_ASSERT(req.event == tracker_request::stopped); + req.listen_port = 0; + if (!m_listen_sockets.empty()) + req.listen_port = m_listen_sockets.front().external_port; + req.key = m_key; + std::string login = i->second->tracker_login(); +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr tl(new tracker_logger(*this)); + m_tracker_loggers.push_back(tl); + m_tracker_manager.queue_request(m_strand, m_half_open, req, login + , m_listen_interface.address(), tl); +#else + m_tracker_manager.queue_request(m_strand, m_half_open, req, login + , m_listen_interface.address()); +#endif + } + } +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << time_now_string() << " sent " << counter << " tracker stop requests\n"; +#endif + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << time_now_string() << " aborting all connections (" << m_connections.size() << ")\n"; +#endif + // abort all connections + while (!m_connections.empty()) + { +#ifndef NDEBUG + int conn = m_connections.size(); +#endif + (*m_connections.begin())->disconnect(); + TORRENT_ASSERT(conn == m_connections.size() + 1); + } + #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " shutting down connection queue\n"; #endif @@ -1513,88 +1553,11 @@ namespace detail } while (!m_abort); - deadline_timer tracker_timer(m_io_service); - #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " locking mutex\n"; #endif session_impl::mutex_t::scoped_lock l(m_mutex); - m_tracker_manager.abort_all_requests(); -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " sending stopped to all torrent's trackers\n"; -#endif - for (std::map >::iterator i = - m_torrents.begin(); i != m_torrents.end(); ++i) - { - i->second->abort(); - // generate a tracker request in case the torrent is not paused - // (in which case it's not currently announced with the tracker) - // or if the torrent itself thinks we should request. Do not build - // a request in case the torrent doesn't have any trackers - if ((!i->second->is_paused() || i->second->should_request()) - && !i->second->trackers().empty()) - { - tracker_request req = i->second->generate_tracker_request(); - TORRENT_ASSERT(!m_listen_sockets.empty()); - req.listen_port = 0; - if (!m_listen_sockets.empty()) - req.listen_port = m_listen_sockets.front().external_port; - req.key = m_key; - std::string login = i->second->tracker_login(); -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr tl(new tracker_logger(*this)); - m_tracker_loggers.push_back(tl); - m_tracker_manager.queue_request(m_strand, m_half_open, req, login - , m_listen_interface.address(), tl); -#else - m_tracker_manager.queue_request(m_strand, m_half_open, req, login - , m_listen_interface.address()); -#endif - } - } - - // close the listen sockets - m_listen_sockets.clear(); - - ptime start(time_now()); - l.unlock(); - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " waiting for trackers to respond (" - << m_settings.stop_tracker_timeout << " seconds timeout)\n"; -#endif - - while (time_now() - start < seconds( - m_settings.stop_tracker_timeout) - && !m_tracker_manager.empty()) - { -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " " << m_tracker_manager.num_requests() - << " tracker requests pending\n"; -#endif - tracker_timer.expires_from_now(milliseconds(100)); - tracker_timer.async_wait(m_strand.wrap( - bind(&io_service::stop, &m_io_service))); - - m_io_service.reset(); - m_io_service.run(); - } - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " tracker shutdown complete, locking mutex\n"; -#endif - - l.lock(); - TORRENT_ASSERT(m_abort); - m_abort = true; - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " cleaning up connections\n"; -#endif - while (!m_connections.empty()) - (*m_connections.begin())->disconnect(); - #ifndef NDEBUG for (torrent_map::iterator i = m_torrents.begin(); i != m_torrents.end(); ++i) diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 5ce539d9e..82c5cc948 100755 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -296,6 +296,7 @@ namespace libtorrent , m_timeout(str.io_service()) , m_completion_timeout(0) , m_read_timeout(0) + , m_abort(false) {} void timeout_handler::set_timeout(int completion_timeout, int read_timeout) @@ -304,10 +305,11 @@ namespace libtorrent m_read_timeout = read_timeout; m_start_time = m_read_time = time_now(); - m_timeout.expires_at((std::min)( - m_read_time + seconds(m_read_timeout) - , m_start_time + seconds((std::min)(m_completion_timeout - , m_read_timeout)))); + if (m_abort) return; + + int timeout = (std::min)( + m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout)); + m_timeout.expires_at(m_read_time + seconds(timeout)); m_timeout.async_wait(m_strand.wrap(bind( &timeout_handler::timeout_callback, self(), _1))); } @@ -319,6 +321,7 @@ namespace libtorrent void timeout_handler::cancel() { + m_abort = true; m_completion_timeout = 0; m_timeout.cancel(); } @@ -341,10 +344,11 @@ namespace libtorrent return; } - m_timeout.expires_at((std::min)( - m_read_time + seconds(m_read_timeout) - , m_start_time + seconds((std::min)(m_completion_timeout - , m_read_timeout)))); + if (m_abort) return; + + int timeout = (std::min)( + m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout)); + m_timeout.expires_at(m_read_time + seconds(timeout)); m_timeout.async_wait(m_strand.wrap( bind(&timeout_handler::timeout_callback, self(), _1))); }