shutdown improvements. Fixes stall

This commit is contained in:
Arvid Norberg 2007-11-02 00:27:53 +00:00
parent c982ba5d90
commit fd51412b70
5 changed files with 76 additions and 96 deletions

View File

@ -184,6 +184,7 @@ namespace libtorrent
typedef boost::mutex mutex_t;
mutable mutex_t m_mutex;
bool m_abort;
};
struct TORRENT_EXPORT tracker_connection

View File

@ -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<entry>::iterator i = std::find_if(m_queue.begin()
, m_queue.end(), boost::bind(&entry::connecting, _1) == false);

View File

@ -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<request_callback> 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

View File

@ -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<tracker_logger> 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<sha1_hash, boost::shared_ptr<torrent> >::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<tracker_logger> 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)

View File

@ -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)));
}