attempt at fixing shutdown hang caused by connection_queue

This commit is contained in:
Arvid Norberg 2012-07-15 23:22:23 +00:00
parent db33922684
commit 0657690b1c
6 changed files with 55 additions and 15 deletions

View File

@ -67,6 +67,22 @@ public:
int limit() const;
void close();
int size() const { return m_queue.size(); }
int num_connecting() const { return m_num_connecting; }
#if defined TORRENT_ASIO_DEBUGGING
float next_timeout() const { return total_milliseconds(m_timer.expires_at() - time_now_hires()) / 1000.f; }
float max_timeout() const
{
ptime max_timeout = min_time();
for (std::list<entry>::const_iterator i = m_queue.begin()
, end(m_queue.end()); i != end; ++i)
{
if (!i->connecting) continue;
if (i->expires > max_timeout) max_timeout = i->expires;
}
if (max_timeout == min_time()) return 0.f;
return total_milliseconds(max_timeout - time_now_hires()) / 1000.f;
}
#endif
#ifdef TORRENT_DEBUG
void check_invariant() const;
@ -85,6 +101,9 @@ private:
entry(): connecting(false), ticket(0), expires(max_time()), priority(0) {}
// called when the connection is initiated
// this is when the timeout countdown starts
// TODO: if we don't actually need the connection queue
// to hold ownership of objects, replace these boost functions
// with pointer to a pure virtual interface class
boost::function<void(int)> on_connect;
// called if done hasn't been called within the timeout
// or if the connection queue aborts. This means there
@ -100,6 +119,9 @@ private:
int priority;
};
// TODO: split this into a queue and connecting map. The key for the map
// is the ticket. Most field in entry would only be necessary for the
// connecting map.
std::list<entry> m_queue;
// the next ticket id a connection will be given
@ -108,6 +130,9 @@ private:
int m_half_open_limit;
bool m_abort;
// the number of outstanding timers
int m_num_timers;
deadline_timer m_timer;
mutable mutex_t m_mutex;

View File

@ -49,6 +49,7 @@ namespace libtorrent
, m_num_connecting(0)
, m_half_open_limit(0)
, m_abort(false)
, m_num_timers(0)
, m_timer(ios)
#ifdef TORRENT_DEBUG
, m_in_timeout_function(false)
@ -155,7 +156,7 @@ namespace libtorrent
continue;
}
TORRENT_TRY {
e.on_timeout();
e.on_connect(-1);
} TORRENT_CATCH(std::exception&) {}
tmp.pop_front();
}
@ -227,6 +228,7 @@ namespace libtorrent
error_code ec;
m_timer.expires_at(expire, ec);
m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
++m_num_timers;
}
i->connecting = true;
++m_num_connecting;
@ -275,6 +277,7 @@ namespace libtorrent
complete_async("connection_queue::on_timeout");
#endif
mutex_t::scoped_lock l(m_mutex);
--m_num_timers;
INVARIANT_CHECK;
#ifdef TORRENT_DEBUG
@ -282,7 +285,7 @@ namespace libtorrent
#endif
TORRENT_ASSERT(!e || e == error::operation_aborted);
if (e) return;
if (e && m_num_connecting == 0 && m_num_timers > 0) return;
ptime next_expire = max_time();
ptime now = time_now_hires() + milliseconds(100);
@ -327,6 +330,7 @@ namespace libtorrent
error_code ec;
m_timer.expires_at(next_expire, ec);
m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
++m_num_timers;
}
try_connect(l);
}

View File

@ -93,6 +93,7 @@ http_connection::http_connection(io_service& ios, connection_queue& cc
http_connection::~http_connection()
{
TORRENT_ASSERT(m_connection_ticket == -1);
#ifdef TORRENT_USE_OPENSSL
if (m_own_ssl_context) delete m_ssl_ctx;
#endif
@ -378,23 +379,14 @@ void http_connection::start(std::string const& hostname, std::string const& port
void http_connection::on_connect_timeout()
{
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
m_connection_ticket = -1;
TORRENT_ASSERT(m_connection_ticket > -1);
// keep ourselves alive even if the callback function
// deletes this object
boost::shared_ptr<http_connection> me(shared_from_this());
if (!m_endpoints.empty())
{
error_code ec;
m_sock.close(ec);
}
else
{
callback(asio::error::timed_out);
close();
}
error_code ec;
m_sock.close(ec);
}
void http_connection::on_timeout(boost::weak_ptr<http_connection> p
@ -550,6 +542,12 @@ void http_connection::queue_connect()
void http_connection::connect(int ticket, tcp::endpoint target_address)
{
if (ticket == -1)
{
close();
return;
}
m_connection_ticket = ticket;
if (m_proxy.proxy_hostnames
&& (m_proxy.type == proxy_settings::socks5

View File

@ -5245,6 +5245,12 @@ namespace libtorrent
(*m_ses.m_logger) << time_now_string() << " ON_CONNECT: " << print_endpoint(m_remote) << "\n";
#endif
if (ticket == -1)
{
disconnect(asio::error::operation_aborted);
return;
}
m_connection_ticket = ticket;
boost::shared_ptr<torrent> t = m_torrent.lock();

View File

@ -5495,7 +5495,9 @@ namespace aux {
{
sleep(1000);
++counter;
printf("\n==== Waiting to shut down: %d ==== conn-queue: %d\n\n", counter, m_half_open.size());
printf("\n==== Waiting to shut down: %d ==== conn-queue: %d connecting: %d timeout (next: %f max: %f)\n\n"
, counter, m_half_open.size(), m_half_open.num_connecting(), m_half_open.next_timeout()
, m_half_open.max_timeout());
}
async_dec_threads();
#endif

View File

@ -776,6 +776,11 @@ void udp_socket::on_connect(int ticket)
if (m_abort) return;
if (is_closed()) return;
if (ticket == -1)
{
close();
return;
}
#if defined TORRENT_ASIO_DEBUGGING
add_outstanding_async("udp_socket::on_connected");